From a213f1ee6c5a1bbe1f074ca201975e76ad2ed50c Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Thu, 12 Jun 2008 09:12:31 +0000
Subject: [PATCH] Refactor XLogOpenRelation() and XLogReadBuffer() in
 preparation for relation forks. XLogOpenRelation() and the associated
 light-weight relation cache in xlogutils.c is gone, and XLogReadBuffer() now
 takes a RelFileNode as argument, instead of Relation.

For functions that still need a Relation struct during WAL replay, there's a
new function called CreateFakeRelcacheEntry() that returns a fake entry like
XLogOpenRelation() used to.
---
 src/backend/access/gin/ginxlog.c       |  42 ++--
 src/backend/access/gist/gist.c         |   6 +-
 src/backend/access/gist/gistutil.c     |  18 +-
 src/backend/access/gist/gistvacuum.c   |   4 +-
 src/backend/access/gist/gistxlog.c     |  32 ++-
 src/backend/access/heap/heapam.c       |  41 ++--
 src/backend/access/heap/pruneheap.c    |   6 +-
 src/backend/access/nbtree/nbtxlog.c    |  61 +++--
 src/backend/access/transam/xlog.c      |  15 +-
 src/backend/access/transam/xlogutils.c | 304 +++++++------------------
 src/backend/commands/sequence.c        |   6 +-
 src/backend/storage/buffer/bufmgr.c    | 109 ++++++---
 src/backend/storage/buffer/localbuf.c  |   8 +-
 src/backend/storage/smgr/smgr.c        |   9 +-
 src/backend/utils/init/flatfiles.c     |  26 +--
 src/include/access/gist_private.h      |   6 +-
 src/include/access/heapam.h            |   4 +-
 src/include/access/xlogutils.h         |  10 +-
 src/include/storage/buf_internals.h    |   9 +-
 src/include/storage/bufmgr.h           |   4 +-
 20 files changed, 294 insertions(+), 426 deletions(-)

diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c
index 8b3d75ce599..428c956c7c6 100644
--- a/src/backend/access/gin/ginxlog.c
+++ b/src/backend/access/gin/ginxlog.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *			 $PostgreSQL: pgsql/src/backend/access/gin/ginxlog.c,v 1.13 2008/05/12 00:00:44 alvherre Exp $
+ *			 $PostgreSQL: pgsql/src/backend/access/gin/ginxlog.c,v 1.14 2008/06/12 09:12:29 heikki Exp $
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
@@ -71,12 +71,10 @@ static void
 ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record)
 {
 	RelFileNode *node = (RelFileNode *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 
-	reln = XLogOpenRelation(*node);
-	buffer = XLogReadBuffer(reln, GIN_ROOT_BLKNO, true);
+	buffer = XLogReadBuffer(*node, GIN_ROOT_BLKNO, true);
 	Assert(BufferIsValid(buffer));
 	page = (Page) BufferGetPage(buffer);
 
@@ -94,12 +92,10 @@ ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record)
 {
 	ginxlogCreatePostingTree *data = (ginxlogCreatePostingTree *) XLogRecGetData(record);
 	ItemPointerData *items = (ItemPointerData *) (XLogRecGetData(record) + sizeof(ginxlogCreatePostingTree));
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 
-	reln = XLogOpenRelation(data->node);
-	buffer = XLogReadBuffer(reln, data->blkno, true);
+	buffer = XLogReadBuffer(data->node, data->blkno, true);
 	Assert(BufferIsValid(buffer));
 	page = (Page) BufferGetPage(buffer);
 
@@ -118,7 +114,6 @@ static void
 ginRedoInsert(XLogRecPtr lsn, XLogRecord *record)
 {
 	ginxlogInsert *data = (ginxlogInsert *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 
@@ -126,8 +121,7 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record)
 	if (record->xl_info & XLR_BKP_BLOCK_1)
 		return;
 
-	reln = XLogOpenRelation(data->node);
-	buffer = XLogReadBuffer(reln, data->blkno, false);
+	buffer = XLogReadBuffer(data->node, data->blkno, false);
 	Assert(BufferIsValid(buffer));
 	page = (Page) BufferGetPage(buffer);
 
@@ -228,26 +222,23 @@ static void
 ginRedoSplit(XLogRecPtr lsn, XLogRecord *record)
 {
 	ginxlogSplit *data = (ginxlogSplit *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		lbuffer,
 				rbuffer;
 	Page		lpage,
 				rpage;
 	uint32		flags = 0;
 
-	reln = XLogOpenRelation(data->node);
-
 	if (data->isLeaf)
 		flags |= GIN_LEAF;
 	if (data->isData)
 		flags |= GIN_DATA;
 
-	lbuffer = XLogReadBuffer(reln, data->lblkno, data->isRootSplit);
+	lbuffer = XLogReadBuffer(data->node, data->lblkno, data->isRootSplit);
 	Assert(BufferIsValid(lbuffer));
 	lpage = (Page) BufferGetPage(lbuffer);
 	GinInitBuffer(lbuffer, flags);
 
-	rbuffer = XLogReadBuffer(reln, data->rblkno, true);
+	rbuffer = XLogReadBuffer(data->node, data->rblkno, true);
 	Assert(BufferIsValid(rbuffer));
 	rpage = (Page) BufferGetPage(rbuffer);
 	GinInitBuffer(rbuffer, flags);
@@ -319,7 +310,7 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record)
 
 	if (data->isRootSplit)
 	{
-		Buffer		rootBuf = XLogReadBuffer(reln, data->rootBlkno, false);
+		Buffer		rootBuf = XLogReadBuffer(data->node, data->rootBlkno, false);
 		Page		rootPage = BufferGetPage(rootBuf);
 
 		GinInitBuffer(rootBuf, flags & ~GIN_LEAF);
@@ -352,7 +343,6 @@ static void
 ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record)
 {
 	ginxlogVacuumPage *data = (ginxlogVacuumPage *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 
@@ -360,8 +350,7 @@ ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record)
 	if (record->xl_info & XLR_BKP_BLOCK_1)
 		return;
 
-	reln = XLogOpenRelation(data->node);
-	buffer = XLogReadBuffer(reln, data->blkno, false);
+	buffer = XLogReadBuffer(data->node, data->blkno, false);
 	Assert(BufferIsValid(buffer));
 	page = (Page) BufferGetPage(buffer);
 
@@ -403,15 +392,12 @@ static void
 ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record)
 {
 	ginxlogDeletePage *data = (ginxlogDeletePage *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 
-	reln = XLogOpenRelation(data->node);
-
 	if (!(record->xl_info & XLR_BKP_BLOCK_1))
 	{
-		buffer = XLogReadBuffer(reln, data->blkno, false);
+		buffer = XLogReadBuffer(data->node, data->blkno, false);
 		page = BufferGetPage(buffer);
 		Assert(GinPageIsData(page));
 		GinPageGetOpaque(page)->flags = GIN_DELETED;
@@ -423,7 +409,7 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record)
 
 	if (!(record->xl_info & XLR_BKP_BLOCK_2))
 	{
-		buffer = XLogReadBuffer(reln, data->parentBlkno, false);
+		buffer = XLogReadBuffer(data->node, data->parentBlkno, false);
 		page = BufferGetPage(buffer);
 		Assert(GinPageIsData(page));
 		Assert(!GinPageIsLeaf(page));
@@ -436,7 +422,7 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record)
 
 	if (!(record->xl_info & XLR_BKP_BLOCK_3) && data->leftBlkno != InvalidBlockNumber)
 	{
-		buffer = XLogReadBuffer(reln, data->leftBlkno, false);
+		buffer = XLogReadBuffer(data->node, data->leftBlkno, false);
 		page = BufferGetPage(buffer);
 		Assert(GinPageIsData(page));
 		GinPageGetOpaque(page)->rightlink = data->rightLink;
@@ -557,9 +543,9 @@ ginContinueSplit(ginIncompleteSplit *split)
 	 * elog(NOTICE,"ginContinueSplit root:%u l:%u r:%u",  split->rootBlkno,
 	 * split->leftBlkno, split->rightBlkno);
 	 */
-	reln = XLogOpenRelation(split->node);
+	buffer = XLogReadBuffer(split->node, split->leftBlkno, false);
 
-	buffer = XLogReadBuffer(reln, split->leftBlkno, false);
+	reln = CreateFakeRelcacheEntry(split->node);
 
 	if (split->rootBlkno == GIN_ROOT_BLKNO)
 	{
@@ -581,6 +567,8 @@ ginContinueSplit(ginIncompleteSplit *split)
 									   GinPageGetOpaque(page)->maxoff))->key;
 	}
 
+	FreeFakeRelcacheEntry(reln);
+
 	btree.rightblkno = split->rightBlkno;
 
 	stack.blkno = split->leftBlkno;
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 1638c4cf0c1..7dd981a490b 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.150 2008/05/12 00:00:44 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.151 2008/06/12 09:12:29 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -462,7 +462,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
 
 		if (!is_leaf)
 			PageIndexTupleDelete(state->stack->page, state->stack->childoffnum);
-		gistfillbuffer(state->r, state->stack->page, state->itup, state->ituplen, InvalidOffsetNumber);
+		gistfillbuffer(state->stack->page, state->itup, state->ituplen, InvalidOffsetNumber);
 
 		MarkBufferDirty(state->stack->buffer);
 
@@ -1008,7 +1008,7 @@ gistnewroot(Relation r, Buffer buffer, IndexTuple *itup, int len, ItemPointer ke
 	START_CRIT_SECTION();
 
 	GISTInitBuffer(buffer, 0);
-	gistfillbuffer(r, page, itup, len, FirstOffsetNumber);
+	gistfillbuffer(page, itup, len, FirstOffsetNumber);
 
 	MarkBufferDirty(buffer);
 
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 9847e412e2f..ef60b6b96d1 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *			$PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.26 2008/05/12 00:00:44 alvherre Exp $
+ *			$PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.27 2008/06/12 09:12:29 heikki Exp $
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
@@ -27,11 +27,10 @@ static Datum attrS[INDEX_MAX_KEYS];
 static bool isnullS[INDEX_MAX_KEYS];
 
 /*
- * Write itup vector to page, has no control of free space
+ * Write itup vector to page, has no control of free space.
  */
-OffsetNumber
-gistfillbuffer(Relation r, Page page, IndexTuple *itup,
-			   int len, OffsetNumber off)
+void
+gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
 	int			i;
@@ -42,14 +41,13 @@ gistfillbuffer(Relation r, Page page, IndexTuple *itup,
 
 	for (i = 0; i < len; i++)
 	{
-		l = PageAddItem(page, (Item) itup[i], IndexTupleSize(itup[i]),
-						off, false, false);
+		Size sz = IndexTupleSize(itup[i]);
+		l = PageAddItem(page, (Item) itup[i], sz, off, false, false);
 		if (l == InvalidOffsetNumber)
-			elog(ERROR, "failed to add item to index page in \"%s\"",
-				 RelationGetRelationName(r));
+			elog(ERROR, "failed to add item to GiST index page, item %d out of %d, size %d bytes",
+				 i, len, sz);
 		off++;
 	}
-	return l;
 }
 
 /*
diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index 809b5ce7cc0..d929962af2a 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.35 2008/05/12 00:00:44 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.36 2008/06/12 09:12:30 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -403,7 +403,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
 			}
 			else
 				/* enough free space */
-				gistfillbuffer(gv->index, tempPage, addon, curlenaddon, InvalidOffsetNumber);
+				gistfillbuffer(tempPage, addon, curlenaddon, InvalidOffsetNumber);
 		}
 	}
 
diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c
index abe912dd88f..801c6e7117c 100644
--- a/src/backend/access/gist/gistxlog.c
+++ b/src/backend/access/gist/gistxlog.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *			 $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.28 2008/05/12 00:00:44 alvherre Exp $
+ *			 $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.29 2008/06/12 09:12:30 heikki Exp $
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
@@ -189,7 +189,6 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot)
 {
 	gistxlogPageUpdate *xldata = (gistxlogPageUpdate *) XLogRecGetData(record);
 	PageUpdateRecord xlrec;
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 
@@ -208,8 +207,7 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot)
 
 	decodePageUpdateRecord(&xlrec, record);
 
-	reln = XLogOpenRelation(xlrec.data->node);
-	buffer = XLogReadBuffer(reln, xlrec.data->blkno, false);
+	buffer = XLogReadBuffer(xlrec.data->node, xlrec.data->blkno, false);
 	if (!BufferIsValid(buffer))
 		return;
 	page = (Page) BufferGetPage(buffer);
@@ -234,7 +232,7 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot)
 
 	/* add tuples */
 	if (xlrec.len > 0)
-		gistfillbuffer(reln, page, xlrec.itup, xlrec.len, InvalidOffsetNumber);
+		gistfillbuffer(page, xlrec.itup, xlrec.len, InvalidOffsetNumber);
 
 	/*
 	 * special case: leafpage, nothing to insert, nothing to delete, then
@@ -262,7 +260,6 @@ static void
 gistRedoPageDeleteRecord(XLogRecPtr lsn, XLogRecord *record)
 {
 	gistxlogPageDelete *xldata = (gistxlogPageDelete *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 
@@ -270,8 +267,7 @@ gistRedoPageDeleteRecord(XLogRecPtr lsn, XLogRecord *record)
 	if (record->xl_info & XLR_BKP_BLOCK_1)
 		return;
 
-	reln = XLogOpenRelation(xldata->node);
-	buffer = XLogReadBuffer(reln, xldata->blkno, false);
+	buffer = XLogReadBuffer(xldata->node, xldata->blkno, false);
 	if (!BufferIsValid(buffer))
 		return;
 
@@ -319,14 +315,12 @@ static void
 gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
 {
 	PageSplitRecord xlrec;
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 	int			i;
 	int			flags;
 
 	decodePageSplitRecord(&xlrec, record);
-	reln = XLogOpenRelation(xlrec.data->node);
 	flags = xlrec.data->origleaf ? F_LEAF : 0;
 
 	/* loop around all pages */
@@ -334,7 +328,7 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
 	{
 		NewPage    *newpage = xlrec.page + i;
 
-		buffer = XLogReadBuffer(reln, newpage->header->blkno, true);
+		buffer = XLogReadBuffer(xlrec.data->node, newpage->header->blkno, true);
 		Assert(BufferIsValid(buffer));
 		page = (Page) BufferGetPage(buffer);
 
@@ -342,7 +336,7 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
 		GISTInitBuffer(buffer, flags);
 
 		/* and fill it */
-		gistfillbuffer(reln, page, newpage->itup, newpage->header->num, FirstOffsetNumber);
+		gistfillbuffer(page, newpage->itup, newpage->header->num, FirstOffsetNumber);
 
 		PageSetLSN(page, lsn);
 		PageSetTLI(page, ThisTimeLineID);
@@ -361,12 +355,10 @@ static void
 gistRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record)
 {
 	RelFileNode *node = (RelFileNode *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 
-	reln = XLogOpenRelation(*node);
-	buffer = XLogReadBuffer(reln, GIST_ROOT_BLKNO, true);
+	buffer = XLogReadBuffer(*node, GIST_ROOT_BLKNO, true);
 	Assert(BufferIsValid(buffer));
 	page = (Page) BufferGetPage(buffer);
 
@@ -602,7 +594,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
 				lenitup;
 	Relation	index;
 
-	index = XLogOpenRelation(insert->node);
+	index = CreateFakeRelcacheEntry(insert->node);
 
 	/*
 	 * needed vector itup never will be more than initial lenblkno+2, because
@@ -624,7 +616,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
 		 * it was split root, so we should only make new root. it can't be
 		 * simple insert into root, we should replace all content of root.
 		 */
-		Buffer		buffer = XLogReadBuffer(index, GIST_ROOT_BLKNO, true);
+		Buffer		buffer = XLogReadBuffer(insert->node, GIST_ROOT_BLKNO, true);
 
 		gistnewroot(index, buffer, itup, lenitup, NULL);
 		UnlockReleaseBuffer(buffer);
@@ -703,7 +695,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
 				LockBuffer(buffers[numbuffer], GIST_EXCLUSIVE);
 				GISTInitBuffer(buffers[numbuffer], 0);
 				pages[numbuffer] = BufferGetPage(buffers[numbuffer]);
-				gistfillbuffer(index, pages[numbuffer], itup, lenitup, FirstOffsetNumber);
+				gistfillbuffer(pages[numbuffer], itup, lenitup, FirstOffsetNumber);
 				numbuffer++;
 
 				if (BufferGetBlockNumber(buffers[0]) == GIST_ROOT_BLKNO)
@@ -749,7 +741,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
 
 				for (j = 0; j < ntodelete; j++)
 					PageIndexTupleDelete(pages[0], todelete[j]);
-				gistfillbuffer(index, pages[0], itup, lenitup, InvalidOffsetNumber);
+				gistfillbuffer(pages[0], itup, lenitup, InvalidOffsetNumber);
 
 				rdata = formUpdateRdata(index->rd_node, buffers[0],
 										todelete, ntodelete,
@@ -794,6 +786,8 @@ gistContinueInsert(gistIncompleteInsert *insert)
 		}
 	}
 
+	FreeFakeRelcacheEntry(index);
+
 	ereport(LOG,
 			(errmsg("index %u/%u/%u needs VACUUM FULL or REINDEX to finish crash recovery",
 			insert->node.spcNode, insert->node.dbNode, insert->node.relNode),
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index c0b46e20e77..9a29a0f209c 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.258 2008/06/08 22:00:47 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.259 2008/06/12 09:12:30 heikki Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -3944,7 +3944,6 @@ static void
 heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record, bool clean_move)
 {
 	xl_heap_clean *xlrec = (xl_heap_clean *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 	OffsetNumber *end;
@@ -3958,8 +3957,7 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record, bool clean_move)
 	if (record->xl_info & XLR_BKP_BLOCK_1)
 		return;
 
-	reln = XLogOpenRelation(xlrec->node);
-	buffer = XLogReadBuffer(reln, xlrec->block, false);
+	buffer = XLogReadBuffer(xlrec->node, xlrec->block, false);
 	if (!BufferIsValid(buffer))
 		return;
 	page = (Page) BufferGetPage(buffer);
@@ -3980,7 +3978,7 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record, bool clean_move)
 	Assert(nunused >= 0);
 
 	/* Update all item pointers per the record, and repair fragmentation */
-	heap_page_prune_execute(reln, buffer,
+	heap_page_prune_execute(buffer,
 							redirected, nredirected,
 							nowdead, ndead,
 							nowunused, nunused,
@@ -4002,15 +4000,13 @@ heap_xlog_freeze(XLogRecPtr lsn, XLogRecord *record)
 {
 	xl_heap_freeze *xlrec = (xl_heap_freeze *) XLogRecGetData(record);
 	TransactionId cutoff_xid = xlrec->cutoff_xid;
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 
 	if (record->xl_info & XLR_BKP_BLOCK_1)
 		return;
 
-	reln = XLogOpenRelation(xlrec->node);
-	buffer = XLogReadBuffer(reln, xlrec->block, false);
+	buffer = XLogReadBuffer(xlrec->node, xlrec->block, false);
 	if (!BufferIsValid(buffer))
 		return;
 	page = (Page) BufferGetPage(buffer);
@@ -4050,7 +4046,6 @@ static void
 heap_xlog_newpage(XLogRecPtr lsn, XLogRecord *record)
 {
 	xl_heap_newpage *xlrec = (xl_heap_newpage *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 
@@ -4058,8 +4053,7 @@ heap_xlog_newpage(XLogRecPtr lsn, XLogRecord *record)
 	 * Note: the NEWPAGE log record is used for both heaps and indexes, so do
 	 * not do anything that assumes we are touching a heap.
 	 */
-	reln = XLogOpenRelation(xlrec->node);
-	buffer = XLogReadBuffer(reln, xlrec->blkno, true);
+	buffer = XLogReadBuffer(xlrec->node, xlrec->blkno, true);
 	Assert(BufferIsValid(buffer));
 	page = (Page) BufferGetPage(buffer);
 
@@ -4076,7 +4070,6 @@ static void
 heap_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
 {
 	xl_heap_delete *xlrec = (xl_heap_delete *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 	OffsetNumber offnum;
@@ -4086,8 +4079,7 @@ heap_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
 	if (record->xl_info & XLR_BKP_BLOCK_1)
 		return;
 
-	reln = XLogOpenRelation(xlrec->target.node);
-	buffer = XLogReadBuffer(reln,
+	buffer = XLogReadBuffer(xlrec->target.node,
 							ItemPointerGetBlockNumber(&(xlrec->target.tid)),
 							false);
 	if (!BufferIsValid(buffer))
@@ -4133,7 +4125,6 @@ static void
 heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
 {
 	xl_heap_insert *xlrec = (xl_heap_insert *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 	OffsetNumber offnum;
@@ -4149,11 +4140,9 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
 	if (record->xl_info & XLR_BKP_BLOCK_1)
 		return;
 
-	reln = XLogOpenRelation(xlrec->target.node);
-
 	if (record->xl_info & XLOG_HEAP_INIT_PAGE)
 	{
-		buffer = XLogReadBuffer(reln,
+		buffer = XLogReadBuffer(xlrec->target.node,
 							 ItemPointerGetBlockNumber(&(xlrec->target.tid)),
 								true);
 		Assert(BufferIsValid(buffer));
@@ -4163,7 +4152,7 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
 	}
 	else
 	{
-		buffer = XLogReadBuffer(reln,
+		buffer = XLogReadBuffer(xlrec->target.node,
 							 ItemPointerGetBlockNumber(&(xlrec->target.tid)),
 								false);
 		if (!BufferIsValid(buffer))
@@ -4216,7 +4205,6 @@ static void
 heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move, bool hot_update)
 {
 	xl_heap_update *xlrec = (xl_heap_update *) XLogRecGetData(record);
-	Relation	reln = XLogOpenRelation(xlrec->target.node);
 	Buffer		buffer;
 	bool		samepage = (ItemPointerGetBlockNumber(&(xlrec->newtid)) ==
 							ItemPointerGetBlockNumber(&(xlrec->target.tid)));
@@ -4242,7 +4230,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move, bool hot_update)
 
 	/* Deal with old tuple version */
 
-	buffer = XLogReadBuffer(reln,
+	buffer = XLogReadBuffer(xlrec->target.node,
 							ItemPointerGetBlockNumber(&(xlrec->target.tid)),
 							false);
 	if (!BufferIsValid(buffer))
@@ -4317,7 +4305,7 @@ newt:;
 
 	if (record->xl_info & XLOG_HEAP_INIT_PAGE)
 	{
-		buffer = XLogReadBuffer(reln,
+		buffer = XLogReadBuffer(xlrec->target.node,
 								ItemPointerGetBlockNumber(&(xlrec->newtid)),
 								true);
 		Assert(BufferIsValid(buffer));
@@ -4327,7 +4315,7 @@ newt:;
 	}
 	else
 	{
-		buffer = XLogReadBuffer(reln,
+		buffer = XLogReadBuffer(xlrec->target.node,
 								ItemPointerGetBlockNumber(&(xlrec->newtid)),
 								false);
 		if (!BufferIsValid(buffer))
@@ -4399,7 +4387,6 @@ static void
 heap_xlog_lock(XLogRecPtr lsn, XLogRecord *record)
 {
 	xl_heap_lock *xlrec = (xl_heap_lock *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 	OffsetNumber offnum;
@@ -4409,8 +4396,7 @@ heap_xlog_lock(XLogRecPtr lsn, XLogRecord *record)
 	if (record->xl_info & XLR_BKP_BLOCK_1)
 		return;
 
-	reln = XLogOpenRelation(xlrec->target.node);
-	buffer = XLogReadBuffer(reln,
+	buffer = XLogReadBuffer(xlrec->target.node,
 							ItemPointerGetBlockNumber(&(xlrec->target.tid)),
 							false);
 	if (!BufferIsValid(buffer))
@@ -4458,7 +4444,6 @@ static void
 heap_xlog_inplace(XLogRecPtr lsn, XLogRecord *record)
 {
 	xl_heap_inplace *xlrec = (xl_heap_inplace *) XLogRecGetData(record);
-	Relation	reln = XLogOpenRelation(xlrec->target.node);
 	Buffer		buffer;
 	Page		page;
 	OffsetNumber offnum;
@@ -4470,7 +4455,7 @@ heap_xlog_inplace(XLogRecPtr lsn, XLogRecord *record)
 	if (record->xl_info & XLR_BKP_BLOCK_1)
 		return;
 
-	buffer = XLogReadBuffer(reln,
+	buffer = XLogReadBuffer(xlrec->target.node,
 							ItemPointerGetBlockNumber(&(xlrec->target.tid)),
 							false);
 	if (!BufferIsValid(buffer))
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index f86c53aad20..2196301c71b 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/heap/pruneheap.c,v 1.13 2008/06/08 22:00:47 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/heap/pruneheap.c,v 1.14 2008/06/12 09:12:30 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -225,7 +225,7 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
 		 * and update the page's hint bit about whether it has free line
 		 * pointers.
 		 */
-		heap_page_prune_execute(relation, buffer,
+		heap_page_prune_execute(buffer,
 								prstate.redirected, prstate.nredirected,
 								prstate.nowdead, prstate.ndead,
 								prstate.nowunused, prstate.nunused,
@@ -696,7 +696,7 @@ heap_prune_record_unused(PruneState *prstate, OffsetNumber offnum)
  * arguments are identical to those of log_heap_clean().
  */
 void
-heap_page_prune_execute(Relation reln, Buffer buffer,
+heap_page_prune_execute(Buffer buffer,
 						OffsetNumber *redirected, int nredirected,
 						OffsetNumber *nowdead, int ndead,
 						OffsetNumber *nowunused, int nunused,
diff --git a/src/backend/access/nbtree/nbtxlog.c b/src/backend/access/nbtree/nbtxlog.c
index 72d292d0965..49021e4885c 100644
--- a/src/backend/access/nbtree/nbtxlog.c
+++ b/src/backend/access/nbtree/nbtxlog.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.51 2008/05/12 00:00:45 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.52 2008/06/12 09:12:30 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -150,7 +150,7 @@ _bt_restore_page(Page page, char *from, int len)
 }
 
 static void
-_bt_restore_meta(Relation reln, XLogRecPtr lsn,
+_bt_restore_meta(RelFileNode rnode, XLogRecPtr lsn,
 				 BlockNumber root, uint32 level,
 				 BlockNumber fastroot, uint32 fastlevel)
 {
@@ -159,7 +159,7 @@ _bt_restore_meta(Relation reln, XLogRecPtr lsn,
 	BTMetaPageData *md;
 	BTPageOpaque pageop;
 
-	metabuf = XLogReadBuffer(reln, BTREE_METAPAGE, true);
+	metabuf = XLogReadBuffer(rnode, BTREE_METAPAGE, true);
 	Assert(BufferIsValid(metabuf));
 	metapg = BufferGetPage(metabuf);
 
@@ -194,7 +194,6 @@ btree_xlog_insert(bool isleaf, bool ismeta,
 				  XLogRecPtr lsn, XLogRecord *record)
 {
 	xl_btree_insert *xlrec = (xl_btree_insert *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 	char	   *datapos;
@@ -220,11 +219,9 @@ btree_xlog_insert(bool isleaf, bool ismeta,
 	if ((record->xl_info & XLR_BKP_BLOCK_1) && !ismeta && isleaf)
 		return;					/* nothing to do */
 
-	reln = XLogOpenRelation(xlrec->target.node);
-
 	if (!(record->xl_info & XLR_BKP_BLOCK_1))
 	{
-		buffer = XLogReadBuffer(reln,
+		buffer = XLogReadBuffer(xlrec->target.node,
 							 ItemPointerGetBlockNumber(&(xlrec->target.tid)),
 								false);
 		if (BufferIsValid(buffer))
@@ -251,7 +248,7 @@ btree_xlog_insert(bool isleaf, bool ismeta,
 	}
 
 	if (ismeta)
-		_bt_restore_meta(reln, lsn,
+		_bt_restore_meta(xlrec->target.node, lsn,
 						 md.root, md.level,
 						 md.fastroot, md.fastlevel);
 
@@ -265,7 +262,6 @@ btree_xlog_split(bool onleft, bool isroot,
 				 XLogRecPtr lsn, XLogRecord *record)
 {
 	xl_btree_split *xlrec = (xl_btree_split *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		rbuf;
 	Page		rpage;
 	BTPageOpaque ropaque;
@@ -277,8 +273,6 @@ btree_xlog_split(bool onleft, bool isroot,
 	Item		left_hikey = NULL;
 	Size		left_hikeysz = 0;
 
-	reln = XLogOpenRelation(xlrec->node);
-
 	datapos = (char *) xlrec + SizeOfBtreeSplit;
 	datalen = record->xl_len - SizeOfBtreeSplit;
 
@@ -328,7 +322,7 @@ btree_xlog_split(bool onleft, bool isroot,
 	}
 
 	/* Reconstruct right (new) sibling from scratch */
-	rbuf = XLogReadBuffer(reln, xlrec->rightsib, true);
+	rbuf = XLogReadBuffer(xlrec->node, xlrec->rightsib, true);
 	Assert(BufferIsValid(rbuf));
 	rpage = (Page) BufferGetPage(rbuf);
 
@@ -369,7 +363,7 @@ btree_xlog_split(bool onleft, bool isroot,
 	 */
 	if (!(record->xl_info & XLR_BKP_BLOCK_1))
 	{
-		Buffer		lbuf = XLogReadBuffer(reln, xlrec->leftsib, false);
+		Buffer		lbuf = XLogReadBuffer(xlrec->node, xlrec->leftsib, false);
 
 		if (BufferIsValid(lbuf))
 		{
@@ -439,7 +433,7 @@ btree_xlog_split(bool onleft, bool isroot,
 	/* Fix left-link of the page to the right of the new right sibling */
 	if (xlrec->rnext != P_NONE && !(record->xl_info & XLR_BKP_BLOCK_2))
 	{
-		Buffer		buffer = XLogReadBuffer(reln, xlrec->rnext, false);
+		Buffer		buffer = XLogReadBuffer(xlrec->node, xlrec->rnext, false);
 
 		if (BufferIsValid(buffer))
 		{
@@ -468,7 +462,6 @@ static void
 btree_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
 {
 	xl_btree_delete *xlrec;
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 	BTPageOpaque opaque;
@@ -477,8 +470,7 @@ btree_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
 		return;
 
 	xlrec = (xl_btree_delete *) XLogRecGetData(record);
-	reln = XLogOpenRelation(xlrec->node);
-	buffer = XLogReadBuffer(reln, xlrec->block, false);
+	buffer = XLogReadBuffer(xlrec->node, xlrec->block, false);
 	if (!BufferIsValid(buffer))
 		return;
 	page = (Page) BufferGetPage(buffer);
@@ -517,7 +509,6 @@ static void
 btree_xlog_delete_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
 {
 	xl_btree_delete_page *xlrec = (xl_btree_delete_page *) XLogRecGetData(record);
-	Relation	reln;
 	BlockNumber parent;
 	BlockNumber target;
 	BlockNumber leftsib;
@@ -526,7 +517,6 @@ btree_xlog_delete_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
 	Page		page;
 	BTPageOpaque pageop;
 
-	reln = XLogOpenRelation(xlrec->target.node);
 	parent = ItemPointerGetBlockNumber(&(xlrec->target.tid));
 	target = xlrec->deadblk;
 	leftsib = xlrec->leftblk;
@@ -535,7 +525,7 @@ btree_xlog_delete_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
 	/* parent page */
 	if (!(record->xl_info & XLR_BKP_BLOCK_1))
 	{
-		buffer = XLogReadBuffer(reln, parent, false);
+		buffer = XLogReadBuffer(xlrec->target.node, parent, false);
 		if (BufferIsValid(buffer))
 		{
 			page = (Page) BufferGetPage(buffer);
@@ -581,7 +571,7 @@ btree_xlog_delete_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
 	/* Fix left-link of right sibling */
 	if (!(record->xl_info & XLR_BKP_BLOCK_2))
 	{
-		buffer = XLogReadBuffer(reln, rightsib, false);
+		buffer = XLogReadBuffer(xlrec->target.node, rightsib, false);
 		if (BufferIsValid(buffer))
 		{
 			page = (Page) BufferGetPage(buffer);
@@ -607,7 +597,7 @@ btree_xlog_delete_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
 	{
 		if (leftsib != P_NONE)
 		{
-			buffer = XLogReadBuffer(reln, leftsib, false);
+			buffer = XLogReadBuffer(xlrec->target.node, leftsib, false);
 			if (BufferIsValid(buffer))
 			{
 				page = (Page) BufferGetPage(buffer);
@@ -630,7 +620,7 @@ btree_xlog_delete_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
 	}
 
 	/* Rewrite target page as empty deleted page */
-	buffer = XLogReadBuffer(reln, target, true);
+	buffer = XLogReadBuffer(xlrec->target.node, target, true);
 	Assert(BufferIsValid(buffer));
 	page = (Page) BufferGetPage(buffer);
 
@@ -655,7 +645,7 @@ btree_xlog_delete_page(uint8 info, XLogRecPtr lsn, XLogRecord *record)
 
 		memcpy(&md, (char *) xlrec + SizeOfBtreeDeletePage,
 			   sizeof(xl_btree_metadata));
-		_bt_restore_meta(reln, lsn,
+		_bt_restore_meta(xlrec->target.node, lsn,
 						 md.root, md.level,
 						 md.fastroot, md.fastlevel);
 	}
@@ -672,14 +662,12 @@ static void
 btree_xlog_newroot(XLogRecPtr lsn, XLogRecord *record)
 {
 	xl_btree_newroot *xlrec = (xl_btree_newroot *) XLogRecGetData(record);
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 	BTPageOpaque pageop;
 	BlockNumber downlink = 0;
 
-	reln = XLogOpenRelation(xlrec->node);
-	buffer = XLogReadBuffer(reln, xlrec->rootblk, true);
+	buffer = XLogReadBuffer(xlrec->node, xlrec->rootblk, true);
 	Assert(BufferIsValid(buffer));
 	page = (Page) BufferGetPage(buffer);
 
@@ -711,7 +699,7 @@ btree_xlog_newroot(XLogRecPtr lsn, XLogRecord *record)
 	MarkBufferDirty(buffer);
 	UnlockReleaseBuffer(buffer);
 
-	_bt_restore_meta(reln, lsn,
+	_bt_restore_meta(xlrec->node, lsn,
 					 xlrec->rootblk, xlrec->level,
 					 xlrec->rootblk, xlrec->level);
 
@@ -904,9 +892,7 @@ btree_xlog_cleanup(void)
 	foreach(l, incomplete_actions)
 	{
 		bt_incomplete_action *action = (bt_incomplete_action *) lfirst(l);
-		Relation	reln;
 
-		reln = XLogOpenRelation(action->node);
 		if (action->is_split)
 		{
 			/* finish an incomplete split */
@@ -917,14 +903,15 @@ btree_xlog_cleanup(void)
 			BTPageOpaque lpageop,
 						rpageop;
 			bool		is_only;
+			Relation	reln;
 
-			lbuf = XLogReadBuffer(reln, action->leftblk, false);
+			lbuf = XLogReadBuffer(action->node, action->leftblk, false);
 			/* failure is impossible because we wrote this page earlier */
 			if (!BufferIsValid(lbuf))
 				elog(PANIC, "btree_xlog_cleanup: left block unfound");
 			lpage = (Page) BufferGetPage(lbuf);
 			lpageop = (BTPageOpaque) PageGetSpecialPointer(lpage);
-			rbuf = XLogReadBuffer(reln, action->rightblk, false);
+			rbuf = XLogReadBuffer(action->node, action->rightblk, false);
 			/* failure is impossible because we wrote this page earlier */
 			if (!BufferIsValid(rbuf))
 				elog(PANIC, "btree_xlog_cleanup: right block unfound");
@@ -934,18 +921,26 @@ btree_xlog_cleanup(void)
 			/* if the pages are all of their level, it's a only-page split */
 			is_only = P_LEFTMOST(lpageop) && P_RIGHTMOST(rpageop);
 
+			reln = CreateFakeRelcacheEntry(action->node);
 			_bt_insert_parent(reln, lbuf, rbuf, NULL,
 							  action->is_root, is_only);
+			FreeFakeRelcacheEntry(reln);
 		}
 		else
 		{
 			/* finish an incomplete deletion (of a half-dead page) */
 			Buffer		buf;
 
-			buf = XLogReadBuffer(reln, action->delblk, false);
+			buf = XLogReadBuffer(action->node, action->delblk, false);
 			if (BufferIsValid(buf))
+			{
+				Relation reln;
+
+				reln = CreateFakeRelcacheEntry(action->node);
 				if (_bt_pagedel(reln, buf, NULL, true) == 0)
 					elog(PANIC, "btree_xlog_cleanup: _bt_pagdel failed");
+				FreeFakeRelcacheEntry(reln);
+			}
 		}
 	}
 	incomplete_actions = NIL;
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 26f0fa72932..4c9b7872ca3 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.313 2008/06/08 22:00:47 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.314 2008/06/12 09:12:30 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2840,7 +2840,6 @@ CleanupBackupHistory(void)
 static void
 RestoreBkpBlocks(XLogRecord *record, XLogRecPtr lsn)
 {
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 	BkpBlock	bkpb;
@@ -2856,8 +2855,7 @@ RestoreBkpBlocks(XLogRecord *record, XLogRecPtr lsn)
 		memcpy(&bkpb, blk, sizeof(BkpBlock));
 		blk += sizeof(BkpBlock);
 
-		reln = XLogOpenRelation(bkpb.node);
-		buffer = XLogReadBuffer(reln, bkpb.block, true);
+		buffer = XLogReadBuffer(bkpb.node, bkpb.block, true);
 		Assert(BufferIsValid(buffer));
 		page = (Page) BufferGetPage(buffer);
 
@@ -5064,9 +5062,7 @@ StartupXLOG(void)
 								BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
 		}
 
-		/* Start up the recovery environment */
-		XLogInitRelationCache();
-
+		/* Initialize resource managers */
 		for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
 		{
 			if (RmgrTable[rmid].rm_startup != NULL)
@@ -5330,11 +5326,6 @@ StartupXLOG(void)
 		 * allows some extra error checking in xlog_redo.
 		 */
 		CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);
-
-		/*
-		 * Close down recovery environment
-		 */
-		XLogCloseRelationCache();
 	}
 
 	/*
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index a73bdb52a46..19758700e7b 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.54 2008/06/08 22:00:47 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.55 2008/06/12 09:12:30 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -190,6 +190,9 @@ XLogCheckInvalidPages(void)
 
 	if (foundone)
 		elog(PANIC, "WAL contains references to invalid pages");
+
+	hash_destroy(invalid_page_tab);
+	invalid_page_tab = NULL;
 }
 
 
@@ -218,27 +221,40 @@ XLogCheckInvalidPages(void)
  * at the end of WAL replay.)
  */
 Buffer
-XLogReadBuffer(Relation reln, BlockNumber blkno, bool init)
+XLogReadBuffer(RelFileNode rnode, BlockNumber blkno, bool init)
 {
-	BlockNumber lastblock = RelationGetNumberOfBlocks(reln);
+	BlockNumber lastblock;
 	Buffer		buffer;
+	SMgrRelation smgr;
 
 	Assert(blkno != P_NEW);
 
+	/* Open the relation at smgr level */
+	smgr = smgropen(rnode);
+
+	/*
+	 * Create the target file if it doesn't already exist.  This lets us cope
+	 * if the replay sequence contains writes to a relation that is later
+	 * deleted.  (The original coding of this routine would instead suppress
+	 * the writes, but that seems like it risks losing valuable data if the
+	 * filesystem loses an inode during a crash.  Better to write the data
+	 * until we are actually told to delete the file.)
+	 */
+	smgrcreate(smgr, false, true);
+
+	lastblock = smgrnblocks(smgr);
+
 	if (blkno < lastblock)
 	{
 		/* page exists in file */
-		if (init)
-			buffer = ReadOrZeroBuffer(reln, blkno);
-		else
-			buffer = ReadBuffer(reln, blkno);
+		buffer = ReadBufferWithoutRelcache(rnode, false, blkno, init);
 	}
 	else
 	{
 		/* hm, page doesn't exist in file */
 		if (!init)
 		{
-			log_invalid_page(reln->rd_node, blkno, false);
+			log_invalid_page(rnode, blkno, false);
 			return InvalidBuffer;
 		}
 		/* OK to extend the file */
@@ -249,7 +265,7 @@ XLogReadBuffer(Relation reln, BlockNumber blkno, bool init)
 		{
 			if (buffer != InvalidBuffer)
 				ReleaseBuffer(buffer);
-			buffer = ReadBuffer(reln, P_NEW);
+			buffer = ReadBufferWithoutRelcache(rnode, false, P_NEW, false);
 			lastblock++;
 		}
 		Assert(BufferGetBlockNumber(buffer) == blkno);
@@ -265,7 +281,7 @@ XLogReadBuffer(Relation reln, BlockNumber blkno, bool init)
 		if (PageIsNew((PageHeader) page))
 		{
 			UnlockReleaseBuffer(buffer);
-			log_invalid_page(reln->rd_node, blkno, true);
+			log_invalid_page(rnode, blkno, true);
 			return InvalidBuffer;
 		}
 	}
@@ -275,226 +291,81 @@ XLogReadBuffer(Relation reln, BlockNumber blkno, bool init)
 
 
 /*
- * Lightweight "Relation" cache --- this substitutes for the normal relcache
- * during XLOG replay.
+ * Struct actually returned by XLogFakeRelcacheEntry, though the declared
+ * return type is Relation.
  */
-
-typedef struct XLogRelDesc
-{
-	RelationData reldata;
-	struct XLogRelDesc *lessRecently;
-	struct XLogRelDesc *moreRecently;
-} XLogRelDesc;
-
-typedef struct XLogRelCacheEntry
+typedef struct
 {
-	RelFileNode rnode;
-	XLogRelDesc *rdesc;
-} XLogRelCacheEntry;
+	RelationData		reldata;	/* Note: this must be first */
+	FormData_pg_class	pgc;
+} FakeRelCacheEntryData;
 
-static HTAB *_xlrelcache;
-static XLogRelDesc *_xlrelarr = NULL;
-static Form_pg_class _xlpgcarr = NULL;
-static int	_xlast = 0;
-static int	_xlcnt = 0;
+typedef FakeRelCacheEntryData *FakeRelCacheEntry;
 
-#define _XLOG_RELCACHESIZE	512
-
-static void
-_xl_init_rel_cache(void)
-{
-	HASHCTL		ctl;
-
-	_xlcnt = _XLOG_RELCACHESIZE;
-	_xlast = 0;
-	_xlrelarr = (XLogRelDesc *) malloc(sizeof(XLogRelDesc) * _xlcnt);
-	memset(_xlrelarr, 0, sizeof(XLogRelDesc) * _xlcnt);
-	_xlpgcarr = (Form_pg_class) malloc(sizeof(FormData_pg_class) * _xlcnt);
-	memset(_xlpgcarr, 0, sizeof(FormData_pg_class) * _xlcnt);
-
-	_xlrelarr[0].moreRecently = &(_xlrelarr[0]);
-	_xlrelarr[0].lessRecently = &(_xlrelarr[0]);
-
-	memset(&ctl, 0, sizeof(ctl));
-	ctl.keysize = sizeof(RelFileNode);
-	ctl.entrysize = sizeof(XLogRelCacheEntry);
-	ctl.hash = tag_hash;
-
-	_xlrelcache = hash_create("XLOG relcache", _XLOG_RELCACHESIZE,
-							  &ctl, HASH_ELEM | HASH_FUNCTION);
-}
-
-static void
-_xl_remove_hash_entry(XLogRelDesc *rdesc)
-{
-	Form_pg_class tpgc = rdesc->reldata.rd_rel;
-	XLogRelCacheEntry *hentry;
-
-	rdesc->lessRecently->moreRecently = rdesc->moreRecently;
-	rdesc->moreRecently->lessRecently = rdesc->lessRecently;
-
-	hentry = (XLogRelCacheEntry *) hash_search(_xlrelcache,
-					  (void *) &(rdesc->reldata.rd_node), HASH_REMOVE, NULL);
-	if (hentry == NULL)
-		elog(PANIC, "_xl_remove_hash_entry: file was not found in cache");
-
-	RelationCloseSmgr(&(rdesc->reldata));
-
-	memset(rdesc, 0, sizeof(XLogRelDesc));
-	memset(tpgc, 0, sizeof(FormData_pg_class));
-	rdesc->reldata.rd_rel = tpgc;
-}
-
-static XLogRelDesc *
-_xl_new_reldesc(void)
-{
-	XLogRelDesc *res;
-
-	_xlast++;
-	if (_xlast < _xlcnt)
-	{
-		_xlrelarr[_xlast].reldata.rd_rel = &(_xlpgcarr[_xlast]);
-		return &(_xlrelarr[_xlast]);
-	}
-
-	/* reuse */
-	res = _xlrelarr[0].moreRecently;
-
-	_xl_remove_hash_entry(res);
-
-	_xlast--;
-	return res;
-}
-
-
-void
-XLogInitRelationCache(void)
-{
-	_xl_init_rel_cache();
-	invalid_page_tab = NULL;
-}
-
-void
-XLogCloseRelationCache(void)
+/*
+ * Create a fake relation cache entry for a physical relation
+ *
+ * It's often convenient to use the same functions in XLOG replay as in the
+ * main codepath, but those functions typically work with a relcache entry. 
+ * We don't have a working relation cache during XLOG replay, but this 
+ * function can be used to create a fake relcache entry instead. Only the 
+ * fields related to physical storage, like rd_rel, are initialized, so the 
+ * fake entry is only usable in low-level operations like ReadBuffer().
+ *
+ * Caller must free the returned entry with FreeFakeRelcacheEntry().
+ */
+Relation
+CreateFakeRelcacheEntry(RelFileNode rnode)
 {
-	HASH_SEQ_STATUS status;
-	XLogRelCacheEntry *hentry;
+	FakeRelCacheEntry fakeentry;
+	Relation rel;
 
-	if (!_xlrelarr)
-		return;
+	/* Allocate the Relation struct and all related space in one block. */
+	fakeentry = palloc0(sizeof(FakeRelCacheEntryData));
+	rel = (Relation) fakeentry;
 
-	hash_seq_init(&status, _xlrelcache);
+	rel->rd_rel = &fakeentry->pgc;
+	rel->rd_node = rnode;
 
-	while ((hentry = (XLogRelCacheEntry *) hash_seq_search(&status)) != NULL)
-		_xl_remove_hash_entry(hentry->rdesc);
+	/* We don't know the name of the relation; use relfilenode instead */
+	sprintf(RelationGetRelationName(rel), "%u", rnode.relNode);
 
-	hash_destroy(_xlrelcache);
+	/*
+	 * We set up the lockRelId in case anything tries to lock the dummy
+	 * relation.  Note that this is fairly bogus since relNode may be
+	 * different from the relation's OID.  It shouldn't really matter
+	 * though, since we are presumably running by ourselves and can't have
+	 * any lock conflicts ...
+	 */
+	rel->rd_lockInfo.lockRelId.dbId = rnode.dbNode;
+	rel->rd_lockInfo.lockRelId.relId = rnode.relNode;
 
-	free(_xlrelarr);
-	free(_xlpgcarr);
+	rel->rd_targblock = InvalidBlockNumber;
+	rel->rd_smgr = NULL;
 
-	_xlrelarr = NULL;
+	return rel;
 }
 
 /*
- * Open a relation during XLOG replay
- *
- * Note: this once had an API that allowed NULL return on failure, but it
- * no longer does; any failure results in elog().
+ * Free a fake relation cache entry.
  */
-Relation
-XLogOpenRelation(RelFileNode rnode)
+void
+FreeFakeRelcacheEntry(Relation fakerel)
 {
-	XLogRelDesc *res;
-	XLogRelCacheEntry *hentry;
-	bool		found;
-
-	hentry = (XLogRelCacheEntry *)
-		hash_search(_xlrelcache, (void *) &rnode, HASH_FIND, NULL);
-
-	if (hentry)
-	{
-		res = hentry->rdesc;
-
-		res->lessRecently->moreRecently = res->moreRecently;
-		res->moreRecently->lessRecently = res->lessRecently;
-	}
-	else
-	{
-		res = _xl_new_reldesc();
-
-		sprintf(RelationGetRelationName(&(res->reldata)), "%u", rnode.relNode);
-
-		res->reldata.rd_node = rnode;
-
-		/*
-		 * We set up the lockRelId in case anything tries to lock the dummy
-		 * relation.  Note that this is fairly bogus since relNode may be
-		 * different from the relation's OID.  It shouldn't really matter
-		 * though, since we are presumably running by ourselves and can't have
-		 * any lock conflicts ...
-		 */
-		res->reldata.rd_lockInfo.lockRelId.dbId = rnode.dbNode;
-		res->reldata.rd_lockInfo.lockRelId.relId = rnode.relNode;
-
-		hentry = (XLogRelCacheEntry *)
-			hash_search(_xlrelcache, (void *) &rnode, HASH_ENTER, &found);
-
-		if (found)
-			elog(PANIC, "xlog relation already present on insert into cache");
-
-		hentry->rdesc = res;
-
-		res->reldata.rd_targblock = InvalidBlockNumber;
-		res->reldata.rd_smgr = NULL;
-		RelationOpenSmgr(&(res->reldata));
-
-		/*
-		 * Create the target file if it doesn't already exist.  This lets us
-		 * cope if the replay sequence contains writes to a relation that is
-		 * later deleted.  (The original coding of this routine would instead
-		 * return NULL, causing the writes to be suppressed. But that seems
-		 * like it risks losing valuable data if the filesystem loses an inode
-		 * during a crash.	Better to write the data until we are actually
-		 * told to delete the file.)
-		 */
-		smgrcreate(res->reldata.rd_smgr, res->reldata.rd_istemp, true);
-	}
-
-	res->moreRecently = &(_xlrelarr[0]);
-	res->lessRecently = _xlrelarr[0].lessRecently;
-	_xlrelarr[0].lessRecently = res;
-	res->lessRecently->moreRecently = res;
-
-	return &(res->reldata);
+	pfree(fakerel);
 }
 
 /*
  * Drop a relation during XLOG replay
  *
- * This is called when the relation is about to be deleted; we need to ensure
- * that there is no dangling smgr reference in the xlog relation cache.
- *
- * Currently, we don't bother to physically remove the relation from the
- * cache, we just let it age out normally.
- *
- * This also takes care of removing any open "invalid-page" records for
- * the relation.
+ * This is called when the relation is about to be deleted; we need to remove
+ * any open "invalid-page" records for the relation.
  */
 void
 XLogDropRelation(RelFileNode rnode)
 {
-	XLogRelCacheEntry *hentry;
-
-	hentry = (XLogRelCacheEntry *)
-		hash_search(_xlrelcache, (void *) &rnode, HASH_FIND, NULL);
-
-	if (hentry)
-	{
-		XLogRelDesc *rdesc = hentry->rdesc;
-
-		RelationCloseSmgr(&(rdesc->reldata));
-	}
+	/* Tell smgr to forget about this relation as well */
+	smgrclosenode(rnode);
 
 	forget_invalid_pages(rnode, 0);
 }
@@ -507,18 +378,14 @@ XLogDropRelation(RelFileNode rnode)
 void
 XLogDropDatabase(Oid dbid)
 {
-	HASH_SEQ_STATUS status;
-	XLogRelCacheEntry *hentry;
-
-	hash_seq_init(&status, _xlrelcache);
-
-	while ((hentry = (XLogRelCacheEntry *) hash_seq_search(&status)) != NULL)
-	{
-		XLogRelDesc *rdesc = hentry->rdesc;
-
-		if (hentry->rnode.dbNode == dbid)
-			RelationCloseSmgr(&(rdesc->reldata));
-	}
+	/*
+	 * This is unnecessarily heavy-handed, as it will close SMgrRelation
+	 * objects for other databases as well. DROP DATABASE occurs seldom
+	 * enough that it's not worth introducing a variant of smgrclose for
+	 * just this purpose. XXX: Or should we rather leave the smgr entries
+	 * dangling?
+	 */
+	smgrcloseall();
 
 	forget_invalid_pages_db(dbid);
 }
@@ -526,8 +393,7 @@ XLogDropDatabase(Oid dbid)
 /*
  * Truncate a relation during XLOG replay
  *
- * We don't need to do anything to the fake relcache, but we do need to
- * clean up any open "invalid-page" records for the dropped pages.
+ * We need to clean up any open "invalid-page" records for the dropped pages.
  */
 void
 XLogTruncateRelation(RelFileNode rnode, BlockNumber nblocks)
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 5d5a3a243c4..cdc60db1e5c 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.152 2008/05/17 01:20:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.153 2008/06/12 09:12:30 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1332,7 +1332,6 @@ void
 seq_redo(XLogRecPtr lsn, XLogRecord *record)
 {
 	uint8		info = record->xl_info & ~XLR_INFO_MASK;
-	Relation	reln;
 	Buffer		buffer;
 	Page		page;
 	char	   *item;
@@ -1343,8 +1342,7 @@ seq_redo(XLogRecPtr lsn, XLogRecord *record)
 	if (info != XLOG_SEQ_LOG)
 		elog(PANIC, "seq_redo: unknown op code %u", info);
 
-	reln = XLogOpenRelation(xlrec->node);
-	buffer = XLogReadBuffer(reln, 0, true);
+	buffer = XLogReadBuffer(xlrec->node, 0, true);
 	Assert(BufferIsValid(buffer));
 	page = (Page) BufferGetPage(buffer);
 
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 7ee888d78d2..a474bd1d3e0 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.231 2008/06/08 22:00:47 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.232 2008/06/12 09:12:31 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -76,9 +76,10 @@ static bool IsForInput;
 static volatile BufferDesc *PinCountWaitBuf = NULL;
 
 
-static Buffer ReadBuffer_common(Relation reln, BlockNumber blockNum,
-				  bool zeroPage,
-				  BufferAccessStrategy strategy);
+static Buffer ReadBuffer_relcache(Relation reln, BlockNumber blockNum,
+				  bool zeroPage, BufferAccessStrategy strategy);
+static Buffer ReadBuffer_common(SMgrRelation reln, bool isLocalBuf, BlockNumber blockNum,
+				  bool zeroPage, 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);
@@ -89,7 +90,7 @@ static bool StartBufferIO(volatile BufferDesc *buf, bool forInput);
 static void TerminateBufferIO(volatile BufferDesc *buf, bool clear_dirty,
 				  int set_flag_bits);
 static void buffer_write_error_callback(void *arg);
-static volatile BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum,
+static volatile BufferDesc *BufferAlloc(SMgrRelation smgr, BlockNumber blockNum,
 			BufferAccessStrategy strategy,
 			bool *foundPtr);
 static void FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln);
@@ -114,7 +115,7 @@ static void AtProcExit_Buffers(int code, Datum arg);
 Buffer
 ReadBuffer(Relation reln, BlockNumber blockNum)
 {
-	return ReadBuffer_common(reln, blockNum, false, NULL);
+	return ReadBuffer_relcache(reln, blockNum, false, NULL);
 }
 
 /*
@@ -125,7 +126,7 @@ Buffer
 ReadBufferWithStrategy(Relation reln, BlockNumber blockNum,
 					   BufferAccessStrategy strategy)
 {
-	return ReadBuffer_common(reln, blockNum, false, strategy);
+	return ReadBuffer_relcache(reln, blockNum, false, strategy);
 }
 
 /*
@@ -142,41 +143,79 @@ ReadBufferWithStrategy(Relation reln, BlockNumber blockNum,
 Buffer
 ReadOrZeroBuffer(Relation reln, BlockNumber blockNum)
 {
-	return ReadBuffer_common(reln, blockNum, true, NULL);
+	return ReadBuffer_relcache(reln, blockNum, true, NULL);
 }
 
 /*
- * ReadBuffer_common -- common logic for ReadBuffer variants
+ * ReadBufferWithoutRelcache -- like ReadBuffer, but doesn't require a 
+ *		relcache entry for the relation. If zeroPage is true, this behaves
+ *		like ReadOrZeroBuffer rather than ReadBuffer.
+ */
+Buffer
+ReadBufferWithoutRelcache(RelFileNode rnode, bool isTemp, 
+						  BlockNumber blockNum, bool zeroPage)
+{
+	bool hit;
+
+	SMgrRelation smgr = smgropen(rnode);
+	return ReadBuffer_common(smgr, isTemp, blockNum, zeroPage, NULL, &hit);
+}
+
+/*
+ * ReadBuffer_relcache -- common logic for ReadBuffer-variants that 
+ *		operate on a Relation.
+ */
+static Buffer
+ReadBuffer_relcache(Relation reln, BlockNumber blockNum, 
+					bool zeroPage, BufferAccessStrategy strategy)
+{
+	bool hit;
+	Buffer buf;
+
+	/* Open it at the smgr level if not already done */
+	RelationOpenSmgr(reln);
+
+	/*
+	 * Read the buffer, and update pgstat counters to reflect a cache
+	 * hit or miss.
+	 */
+	pgstat_count_buffer_read(reln);
+	buf = ReadBuffer_common(reln->rd_smgr, reln->rd_istemp, blockNum, 
+							zeroPage, strategy, &hit);
+	if (hit)
+		pgstat_count_buffer_hit(reln);
+	return buf;
+}
+
+/*
+ * ReadBuffer_common -- common logic for all ReadBuffer variants
+ *
+ * *hit is set to true if the request was satisfied from shared buffer cache.
  */
 static Buffer
-ReadBuffer_common(Relation reln, BlockNumber blockNum, bool zeroPage,
-				  BufferAccessStrategy strategy)
+ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, BlockNumber blockNum, 
+				  bool zeroPage, BufferAccessStrategy strategy, bool *hit)
 {
 	volatile BufferDesc *bufHdr;
 	Block		bufBlock;
 	bool		found;
 	bool		isExtend;
-	bool		isLocalBuf;
+
+	*hit = false;
 
 	/* Make sure we will have room to remember the buffer pin */
 	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
 
 	isExtend = (blockNum == P_NEW);
-	isLocalBuf = reln->rd_istemp;
-
-	/* Open it at the smgr level if not already done */
-	RelationOpenSmgr(reln);
 
 	/* Substitute proper block number if caller asked for P_NEW */
 	if (isExtend)
-		blockNum = smgrnblocks(reln->rd_smgr);
-
-	pgstat_count_buffer_read(reln);
+		blockNum = smgrnblocks(smgr);
 
 	if (isLocalBuf)
 	{
 		ReadLocalBufferCount++;
-		bufHdr = LocalBufferAlloc(reln, blockNum, &found);
+		bufHdr = LocalBufferAlloc(smgr, blockNum, &found);
 		if (found)
 			LocalBufferHitCount++;
 	}
@@ -188,7 +227,7 @@ ReadBuffer_common(Relation reln, BlockNumber blockNum, bool zeroPage,
 		 * lookup the buffer.  IO_IN_PROGRESS is set if the requested block is
 		 * not currently in memory.
 		 */
-		bufHdr = BufferAlloc(reln, blockNum, strategy, &found);
+		bufHdr = BufferAlloc(smgr, blockNum, strategy, &found);
 		if (found)
 			BufferHitCount++;
 	}
@@ -201,7 +240,7 @@ ReadBuffer_common(Relation reln, BlockNumber blockNum, bool zeroPage,
 		if (!isExtend)
 		{
 			/* Just need to update stats before we exit */
-			pgstat_count_buffer_hit(reln);
+			*hit = true;
 
 			if (VacuumCostActive)
 				VacuumCostBalance += VacuumCostPageHit;
@@ -225,8 +264,8 @@ ReadBuffer_common(Relation reln, BlockNumber blockNum, bool zeroPage,
 		bufBlock = isLocalBuf ? LocalBufHdrGetBlock(bufHdr) : BufHdrGetBlock(bufHdr);
 		if (!PageIsNew((PageHeader) bufBlock))
 			ereport(ERROR,
-					(errmsg("unexpected data beyond EOF in block %u of relation \"%s\"",
-							blockNum, RelationGetRelationName(reln)),
+					(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),
 					 errhint("This has been seen to occur with buggy kernels; consider updating your system.")));
 
 		/*
@@ -278,8 +317,7 @@ ReadBuffer_common(Relation reln, BlockNumber blockNum, bool zeroPage,
 	{
 		/* new buffers are zero-filled */
 		MemSet((char *) bufBlock, 0, BLCKSZ);
-		smgrextend(reln->rd_smgr, blockNum, (char *) bufBlock,
-				   reln->rd_istemp);
+		smgrextend(smgr, blockNum, (char *) bufBlock, isLocalBuf);
 	}
 	else
 	{
@@ -290,7 +328,7 @@ ReadBuffer_common(Relation reln, BlockNumber blockNum, bool zeroPage,
 		if (zeroPage)
 			MemSet((char *) bufBlock, 0, BLCKSZ);
 		else
-			smgrread(reln->rd_smgr, blockNum, (char *) bufBlock);
+			smgrread(smgr, blockNum, (char *) bufBlock);
 		/* check for garbage data */
 		if (!PageHeaderIsValid((PageHeader) bufBlock))
 		{
@@ -298,15 +336,20 @@ ReadBuffer_common(Relation reln, BlockNumber blockNum, bool zeroPage,
 			{
 				ereport(WARNING,
 						(errcode(ERRCODE_DATA_CORRUPTED),
-						 errmsg("invalid page header in block %u of relation \"%s\"; zeroing out page",
-								blockNum, RelationGetRelationName(reln))));
+						 errmsg("invalid page header in block %u of relation %u/%u/%u; zeroing out page",
+								blockNum, 
+								smgr->smgr_rnode.spcNode,
+								smgr->smgr_rnode.dbNode,
+								smgr->smgr_rnode.relNode)));
 				MemSet((char *) bufBlock, 0, BLCKSZ);
 			}
 			else
 				ereport(ERROR,
 						(errcode(ERRCODE_DATA_CORRUPTED),
-				 errmsg("invalid page header in block %u of relation \"%s\"",
-						blockNum, RelationGetRelationName(reln))));
+				 errmsg("invalid page header in block %u of relation %u/%u/%u",
+						blockNum, smgr->smgr_rnode.spcNode,
+						smgr->smgr_rnode.dbNode,
+						smgr->smgr_rnode.relNode)));
 		}
 	}
 
@@ -347,7 +390,7 @@ ReadBuffer_common(Relation reln, BlockNumber blockNum, bool zeroPage,
  * No locks are held either at entry or exit.
  */
 static volatile BufferDesc *
-BufferAlloc(Relation reln,
+BufferAlloc(SMgrRelation smgr,
 			BlockNumber blockNum,
 			BufferAccessStrategy strategy,
 			bool *foundPtr)
@@ -364,7 +407,7 @@ BufferAlloc(Relation reln,
 	bool		valid;
 
 	/* create a tag so we can lookup the buffer */
-	INIT_BUFFERTAG(newTag, reln, blockNum);
+	INIT_BUFFERTAG(newTag, smgr->smgr_rnode, blockNum);
 
 	/* determine its hash code and partition lock ID */
 	newHash = BufTableHashCode(&newTag);
diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c
index a6f76f5689e..ae5f3049a5f 100644
--- a/src/backend/storage/buffer/localbuf.c
+++ b/src/backend/storage/buffer/localbuf.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.79 2008/01/01 19:45:51 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.80 2008/06/12 09:12:31 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,7 +61,7 @@ static Block GetLocalBufferStorage(void);
  * (hence, usage_count is always advanced).
  */
 BufferDesc *
-LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
+LocalBufferAlloc(SMgrRelation smgr, BlockNumber blockNum, bool *foundPtr)
 {
 	BufferTag	newTag;			/* identity of requested block */
 	LocalBufferLookupEnt *hresult;
@@ -70,7 +70,7 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
 	int			trycounter;
 	bool		found;
 
-	INIT_BUFFERTAG(newTag, reln, blockNum);
+	INIT_BUFFERTAG(newTag, smgr->smgr_rnode, blockNum);
 
 	/* Initialize local buffers if first request in this session */
 	if (LocalBufHash == NULL)
@@ -87,7 +87,7 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
 		Assert(BUFFERTAGS_EQUAL(bufHdr->tag, newTag));
 #ifdef LBDEBUG
 		fprintf(stderr, "LB ALLOC (%u,%d) %d\n",
-				RelationGetRelid(reln), blockNum, -b - 1);
+				smgr->smgr_rnode.relNode, blockNum, -b - 1);
 #endif
 		/* this part is equivalent to PinBuffer for a shared buffer */
 		if (LocalRefCount[b] == 0)
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index 3f57a2d1b39..d0282f8a6d7 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.109 2008/01/01 19:45:52 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.110 2008/06/12 09:12:31 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -330,6 +330,13 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
 	xl_smgr_create xlrec;
 	PendingRelDelete *pending;
 
+	/*
+	 * Exit quickly in WAL replay mode if we've already opened the file. 
+	 * If it's open, it surely must exist.
+	 */ 
+	if (isRedo && reln->md_fd != NULL)
+		return;
+
 	/*
 	 * We may be using the target table space for the first time in this
 	 * database, so create a per-database subdirectory if needed.
diff --git a/src/backend/utils/init/flatfiles.c b/src/backend/utils/init/flatfiles.c
index c39ff68fe01..009c6a91bf6 100644
--- a/src/backend/utils/init/flatfiles.c
+++ b/src/backend/utils/init/flatfiles.c
@@ -23,7 +23,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.34 2008/05/12 00:00:52 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.35 2008/06/12 09:12:31 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -704,12 +704,6 @@ BuildFlatFiles(bool database_only)
 				rel_authid,
 				rel_authmem;
 
-	/*
-	 * We don't have any hope of running a real relcache, but we can use the
-	 * same fake-relcache facility that WAL replay uses.
-	 */
-	XLogInitRelationCache();
-
 	/* Need a resowner to keep the heapam and buffer code happy */
 	owner = ResourceOwnerCreate(NULL, "BuildFlatFiles");
 	CurrentResourceOwner = owner;
@@ -719,9 +713,15 @@ BuildFlatFiles(bool database_only)
 	rnode.dbNode = 0;
 	rnode.relNode = DatabaseRelationId;
 
-	/* No locking is needed because no one else is alive yet */
-	rel_db = XLogOpenRelation(rnode);
+	/*
+	 * We don't have any hope of running a real relcache, but we can use the
+	 * same fake-relcache facility that WAL replay uses.
+	 *
+	 * No locking is needed because no one else is alive yet.
+	 */
+	rel_db = CreateFakeRelcacheEntry(rnode);
 	write_database_file(rel_db, true);
+	FreeFakeRelcacheEntry(rel_db);
 
 	if (!database_only)
 	{
@@ -729,21 +729,21 @@ BuildFlatFiles(bool database_only)
 		rnode.spcNode = GLOBALTABLESPACE_OID;
 		rnode.dbNode = 0;
 		rnode.relNode = AuthIdRelationId;
-		rel_authid = XLogOpenRelation(rnode);
+		rel_authid = CreateFakeRelcacheEntry(rnode);
 
 		/* hard-wired path to pg_auth_members */
 		rnode.spcNode = GLOBALTABLESPACE_OID;
 		rnode.dbNode = 0;
 		rnode.relNode = AuthMemRelationId;
-		rel_authmem = XLogOpenRelation(rnode);
+		rel_authmem = CreateFakeRelcacheEntry(rnode);
 
 		write_auth_file(rel_authid, rel_authmem);
+		FreeFakeRelcacheEntry(rel_authid);
+		FreeFakeRelcacheEntry(rel_authmem);
 	}
 
 	CurrentResourceOwner = NULL;
 	ResourceOwnerDelete(owner);
-
-	XLogCloseRelationCache();
 }
 
 
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index b34388b4ed1..03d201779a4 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.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/access/gist_private.h,v 1.29 2008/04/10 22:25:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.30 2008/06/12 09:12:31 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -284,8 +284,8 @@ extern bool gistfitpage(IndexTuple *itvec, int len);
 extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace);
 extern void gistcheckpage(Relation rel, Buffer buf);
 extern Buffer gistNewBuffer(Relation r);
-extern OffsetNumber gistfillbuffer(Relation r, Page page, IndexTuple *itup,
-			   int len, OffsetNumber off);
+extern void gistfillbuffer(Page page, IndexTuple *itup, int len,
+						   OffsetNumber off);
 extern IndexTuple *gistextractpage(Page page, int *len /* out */ );
 extern IndexTuple *gistjoinvector(
 			   IndexTuple *itvec, int *len,
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index 22026901874..17e4a735e92 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.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/access/heapam.h,v 1.135 2008/06/06 22:35:22 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.136 2008/06/12 09:12:31 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -124,7 +124,7 @@ extern void heap_page_prune_opt(Relation relation, Buffer buffer,
 extern int heap_page_prune(Relation relation, Buffer buffer,
 				TransactionId OldestXmin,
 				bool redirect_move, bool report_stats);
-extern void heap_page_prune_execute(Relation reln, Buffer buffer,
+extern void heap_page_prune_execute(Buffer buffer,
 						OffsetNumber *redirected, int nredirected,
 						OffsetNumber *nowdead, int ndead,
 						OffsetNumber *nowunused, int nunused,
diff --git a/src/include/access/xlogutils.h b/src/include/access/xlogutils.h
index 952c7f22e98..b2d5c3be0f1 100644
--- a/src/include/access/xlogutils.h
+++ b/src/include/access/xlogutils.h
@@ -6,7 +6,7 @@
  * 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.23 2008/01/01 19:45:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/xlogutils.h,v 1.24 2008/06/12 09:12:31 heikki Exp $
  */
 #ifndef XLOG_UTILS_H
 #define XLOG_UTILS_H
@@ -15,15 +15,15 @@
 #include "utils/rel.h"
 
 
-extern void XLogInitRelationCache(void);
 extern void XLogCheckInvalidPages(void);
-extern void XLogCloseRelationCache(void);
 
-extern Relation XLogOpenRelation(RelFileNode rnode);
 extern void XLogDropRelation(RelFileNode rnode);
 extern void XLogDropDatabase(Oid dbid);
 extern void XLogTruncateRelation(RelFileNode rnode, BlockNumber nblocks);
 
-extern Buffer XLogReadBuffer(Relation reln, BlockNumber blkno, bool init);
+extern Buffer XLogReadBuffer(RelFileNode rnode, BlockNumber blkno, bool init);
+
+extern Relation CreateFakeRelcacheEntry(RelFileNode rnode);
+extern void FreeFakeRelcacheEntry(Relation fakerel);
 
 #endif
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index 5178a4d5dc2..472e64de1bd 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -8,7 +8,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/buf_internals.h,v 1.95 2008/01/01 19:45:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/buf_internals.h,v 1.96 2008/06/12 09:12:31 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "storage/buf.h"
 #include "storage/lwlock.h"
 #include "storage/shmem.h"
+#include "storage/smgr.h"
 #include "storage/spin.h"
 #include "utils/rel.h"
 
@@ -75,9 +76,9 @@ typedef struct buftag
 	(a).blockNum = InvalidBlockNumber \
 )
 
-#define INIT_BUFFERTAG(a,xx_reln,xx_blockNum) \
+#define INIT_BUFFERTAG(a,xx_rnode,xx_blockNum) \
 ( \
-	(a).rnode = (xx_reln)->rd_node, \
+	(a).rnode = (xx_rnode), \
 	(a).blockNum = (xx_blockNum) \
 )
 
@@ -201,7 +202,7 @@ extern int	BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id);
 extern void BufTableDelete(BufferTag *tagPtr, uint32 hashcode);
 
 /* localbuf.c */
-extern BufferDesc *LocalBufferAlloc(Relation reln, BlockNumber blockNum,
+extern BufferDesc *LocalBufferAlloc(SMgrRelation reln, BlockNumber blockNum,
 				 bool *foundPtr);
 extern void MarkLocalBufferDirty(Buffer buffer);
 extern void DropRelFileNodeLocalBuffers(RelFileNode rnode,
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index d503d56eba7..29d8bea287f 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.112 2008/06/08 22:00:48 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.113 2008/06/12 09:12:31 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -145,6 +145,8 @@ extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
 extern Buffer ReadBufferWithStrategy(Relation reln, BlockNumber blockNum,
 					   BufferAccessStrategy strategy);
 extern Buffer ReadOrZeroBuffer(Relation reln, BlockNumber blockNum);
+extern Buffer ReadBufferWithoutRelcache(RelFileNode rnode, bool isTemp,
+							 BlockNumber blockNum, bool zeroPage);
 extern void ReleaseBuffer(Buffer buffer);
 extern void UnlockReleaseBuffer(Buffer buffer);
 extern void MarkBufferDirty(Buffer buffer);
-- 
GitLab