From 3396000684b41e7e9467d1abc67152b39e697035 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Wed, 19 Nov 2008 10:34:52 +0000
Subject: [PATCH] Rethink the way FSM truncation works. Instead of WAL-logging
 FSM truncations in FSM code, call FreeSpaceMapTruncateRel from smgr_redo. To
 make that cleaner from modularity point of view, move the WAL-logging one
 level up to RelationTruncate, and move RelationTruncate and all the related
 WAL-logging to new src/backend/catalog/storage.c file. Introduce new
 RelationCreateStorage and RelationDropStorage functions that are used instead
 of calling smgrcreate/smgrscheduleunlink directly. Move the pending rel
 deletion stuff from smgrcreate/smgrscheduleunlink to the new functions. This
 leaves smgr.c as a thin wrapper around md.c; all the transactional stuff is
 now in storage.c.

This will make it easier to add new forks with similar truncation logic,
like the visibility map.
---
 src/backend/access/gin/gininsert.c        |   5 +-
 src/backend/access/gin/ginvacuum.c        |   4 +-
 src/backend/access/gist/gist.c            |   5 +-
 src/backend/access/gist/gistvacuum.c      |   4 +-
 src/backend/access/heap/heapam.c          |   6 +-
 src/backend/access/nbtree/nbtree.c        |   7 +-
 src/backend/access/transam/rmgr.c         |   6 +-
 src/backend/access/transam/twophase.c     |  73 ++--
 src/backend/access/transam/xact.c         |  48 ++-
 src/backend/access/transam/xlogutils.c    |   4 +-
 src/backend/catalog/Makefile              |   4 +-
 src/backend/catalog/heap.c                |  27 +-
 src/backend/catalog/index.c               |  42 +-
 src/backend/catalog/storage.c             | 462 ++++++++++++++++++++++
 src/backend/commands/tablecmds.c          |  21 +-
 src/backend/commands/vacuum.c             |   5 +-
 src/backend/commands/vacuumlazy.c         |   4 +-
 src/backend/rewrite/rewriteDefine.c       |  15 +-
 src/backend/storage/buffer/bufmgr.c       |  24 +-
 src/backend/storage/freespace/freespace.c | 157 ++------
 src/backend/storage/freespace/indexfsm.c  |  28 +-
 src/backend/storage/smgr/smgr.c           | 420 +-------------------
 src/include/access/rmgr.h                 |   3 +-
 src/include/access/xact.h                 |  14 +-
 src/include/catalog/storage.h             |  39 ++
 src/include/storage/bufmgr.h              |   3 +-
 src/include/storage/freespace.h           |   6 +-
 src/include/storage/indexfsm.h            |   4 +-
 src/include/storage/relfilenode.h         |  11 +-
 src/include/storage/smgr.h                |  18 +-
 30 files changed, 675 insertions(+), 794 deletions(-)
 create mode 100644 src/backend/catalog/storage.c
 create mode 100644 src/include/catalog/storage.h

diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index 6e0a194a694..54bfa928531 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *			$PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.16 2008/11/13 17:42:09 tgl Exp $
+ *			$PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.17 2008/11/19 10:34:50 heikki Exp $
  *-------------------------------------------------------------------------
  */
 
@@ -284,9 +284,6 @@ ginbuild(PG_FUNCTION_ARGS)
 		elog(ERROR, "index \"%s\" already contains data",
 			 RelationGetRelationName(index));
 
-	/* Initialize FSM */
-	InitIndexFreeSpaceMap(index);
-
 	initGinState(&buildstate.ginstate, index);
 
 	/* initialize the root page */
diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c
index c49926c3fd2..4cc9aaf47d7 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *			$PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.25 2008/11/03 20:47:48 tgl Exp $
+ *			$PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.26 2008/11/19 10:34:50 heikki Exp $
  *-------------------------------------------------------------------------
  */
 
@@ -16,6 +16,7 @@
 
 #include "access/genam.h"
 #include "access/gin.h"
+#include "catalog/storage.h"
 #include "commands/vacuum.h"
 #include "miscadmin.h"
 #include "storage/bufmgr.h"
@@ -757,7 +758,6 @@ ginvacuumcleanup(PG_FUNCTION_ARGS)
 	if (info->vacuum_full && lastBlock > lastFilledBlock)
 	{
 		/* try to truncate index */
-		FreeSpaceMapTruncateRel(index, lastFilledBlock + 1);
 		RelationTruncate(index, lastFilledBlock + 1);
 
 		stats->pages_removed = lastBlock - lastFilledBlock;
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 1dff6d2f2ae..1b5946e8896 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.154 2008/11/13 17:42:09 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.155 2008/11/19 10:34:50 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -103,9 +103,6 @@ gistbuild(PG_FUNCTION_ARGS)
 		elog(ERROR, "index \"%s\" already contains data",
 			 RelationGetRelationName(index));
 
-	/* Initialize FSM */
-	InitIndexFreeSpaceMap(index);
-
 	/* no locking is needed */
 	initGISTstate(&buildstate.giststate, index);
 
diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index d933fea25b2..e6f3502f82f 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.40 2008/11/03 20:47:48 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.41 2008/11/19 10:34:50 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,7 @@
 
 #include "access/genam.h"
 #include "access/gist_private.h"
+#include "catalog/storage.h"
 #include "commands/vacuum.h"
 #include "miscadmin.h"
 #include "storage/bufmgr.h"
@@ -603,7 +604,6 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
 
 	if (info->vacuum_full && lastFilledBlock < lastBlock)
 	{							/* try to truncate index */
-		FreeSpaceMapTruncateRel(rel, lastFilledBlock + 1);
 		RelationTruncate(rel, lastFilledBlock + 1);
 
 		stats->std.pages_removed = lastBlock - lastFilledBlock;
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 7139b03471e..f6d75c6e2b2 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.269 2008/11/06 20:51:14 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.270 2008/11/19 10:34:50 heikki Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -4863,8 +4863,7 @@ heap_sync(Relation rel)
 	/* FlushRelationBuffers will have opened rd_smgr */
 	smgrimmedsync(rel->rd_smgr, MAIN_FORKNUM);
 
-	/* sync FSM as well */
-	smgrimmedsync(rel->rd_smgr, FSM_FORKNUM);
+	/* FSM is not critical, don't bother syncing it */
 
 	/* toast heap, if any */
 	if (OidIsValid(rel->rd_rel->reltoastrelid))
@@ -4874,7 +4873,6 @@ heap_sync(Relation rel)
 		toastrel = heap_open(rel->rd_rel->reltoastrelid, AccessShareLock);
 		FlushRelationBuffers(toastrel);
 		smgrimmedsync(toastrel->rd_smgr, MAIN_FORKNUM);
-		smgrimmedsync(toastrel->rd_smgr, FSM_FORKNUM);
 		heap_close(toastrel, AccessShareLock);
 	}
 }
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index bd486afabb7..32a92d8cc20 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.165 2008/11/13 17:42:10 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.166 2008/11/19 10:34:50 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,6 +22,7 @@
 #include "access/nbtree.h"
 #include "access/relscan.h"
 #include "catalog/index.h"
+#include "catalog/storage.h"
 #include "commands/vacuum.h"
 #include "miscadmin.h"
 #include "storage/bufmgr.h"
@@ -109,9 +110,6 @@ btbuild(PG_FUNCTION_ARGS)
 		elog(ERROR, "index \"%s\" already contains data",
 			 RelationGetRelationName(index));
 
-	/* Initialize FSM */
-	InitIndexFreeSpaceMap(index);
-
 	buildstate.spool = _bt_spoolinit(index, indexInfo->ii_Unique, false);
 
 	/*
@@ -696,7 +694,6 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 		/*
 		 * Okay to truncate.
 		 */
-		FreeSpaceMapTruncateRel(rel, new_pages);
 		RelationTruncate(rel, new_pages);
 
 		/* update statistics */
diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c
index 7c62ec38543..44c3cd7769a 100644
--- a/src/backend/access/transam/rmgr.c
+++ b/src/backend/access/transam/rmgr.c
@@ -3,7 +3,7 @@
  *
  * Resource managers definition
  *
- * $PostgreSQL: pgsql/src/backend/access/transam/rmgr.c,v 1.26 2008/09/30 10:52:11 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/rmgr.c,v 1.27 2008/11/19 10:34:50 heikki Exp $
  */
 #include "postgres.h"
 
@@ -16,11 +16,11 @@
 #include "access/nbtree.h"
 #include "access/xact.h"
 #include "access/xlog_internal.h"
+#include "catalog/storage.h"
 #include "commands/dbcommands.h"
 #include "commands/sequence.h"
 #include "commands/tablespace.h"
 #include "storage/freespace.h"
-#include "storage/smgr.h"
 
 
 const RmgrData RmgrTable[RM_MAX_ID + 1] = {
@@ -31,7 +31,7 @@ const RmgrData RmgrTable[RM_MAX_ID + 1] = {
 	{"Database", dbase_redo, dbase_desc, NULL, NULL, NULL},
 	{"Tablespace", tblspc_redo, tblspc_desc, NULL, NULL, NULL},
 	{"MultiXact", multixact_redo, multixact_desc, NULL, NULL, NULL},
-	{"FreeSpaceMap", fsm_redo, fsm_desc, NULL, NULL, NULL},
+	{"Reserved 7", NULL, NULL, NULL, NULL, NULL},
 	{"Reserved 8", NULL, NULL, NULL, NULL, NULL},
 	{"Heap2", heap2_redo, heap2_desc, NULL, NULL, NULL},
 	{"Heap", heap_redo, heap_desc, NULL, NULL, NULL},
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 11480098446..369fe97588a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *		$PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.47 2008/11/02 21:24:51 tgl Exp $
+ *		$PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.48 2008/11/19 10:34:50 heikki Exp $
  *
  * NOTES
  *		Each global transaction is associated with a global transaction
@@ -48,7 +48,9 @@
 #include "access/twophase.h"
 #include "access/twophase_rmgr.h"
 #include "access/xact.h"
+#include "access/xlogutils.h"
 #include "catalog/pg_type.h"
+#include "catalog/storage.h"
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "pg_trace.h"
@@ -141,12 +143,12 @@ static void RecordTransactionCommitPrepared(TransactionId xid,
 								int nchildren,
 								TransactionId *children,
 								int nrels,
-								RelFileFork *rels);
+								RelFileNode *rels);
 static void RecordTransactionAbortPrepared(TransactionId xid,
 							   int nchildren,
 							   TransactionId *children,
 							   int nrels,
-							   RelFileFork *rels);
+							   RelFileNode *rels);
 static void ProcessRecords(char *bufptr, TransactionId xid,
 			   const TwoPhaseCallback callbacks[]);
 
@@ -694,8 +696,8 @@ TwoPhaseGetDummyProc(TransactionId xid)
  *
  *	1. TwoPhaseFileHeader
  *	2. TransactionId[] (subtransactions)
- *	3. RelFileFork[] (files to be deleted at commit)
- *	4. RelFileFork[] (files to be deleted at abort)
+ *	3. RelFileNode[] (files to be deleted at commit)
+ *	4. RelFileNode[] (files to be deleted at abort)
  *	5. TwoPhaseRecordOnDisk
  *	6. ...
  *	7. TwoPhaseRecordOnDisk (end sentinel, rmid == TWOPHASE_RM_END_ID)
@@ -793,8 +795,8 @@ StartPrepare(GlobalTransaction gxact)
 	TransactionId xid = gxact->proc.xid;
 	TwoPhaseFileHeader hdr;
 	TransactionId *children;
-	RelFileFork *commitrels;
-	RelFileFork *abortrels;
+	RelFileNode *commitrels;
+	RelFileNode *abortrels;
 
 	/* Initialize linked list */
 	records.head = palloc0(sizeof(XLogRecData));
@@ -832,12 +834,12 @@ StartPrepare(GlobalTransaction gxact)
 	}
 	if (hdr.ncommitrels > 0)
 	{
-		save_state_data(commitrels, hdr.ncommitrels * sizeof(RelFileFork));
+		save_state_data(commitrels, hdr.ncommitrels * sizeof(RelFileNode));
 		pfree(commitrels);
 	}
 	if (hdr.nabortrels > 0)
 	{
-		save_state_data(abortrels, hdr.nabortrels * sizeof(RelFileFork));
+		save_state_data(abortrels, hdr.nabortrels * sizeof(RelFileNode));
 		pfree(abortrels);
 	}
 }
@@ -1140,8 +1142,10 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
 	TwoPhaseFileHeader *hdr;
 	TransactionId latestXid;
 	TransactionId *children;
-	RelFileFork *commitrels;
-	RelFileFork *abortrels;
+	RelFileNode *commitrels;
+	RelFileNode *abortrels;
+	RelFileNode *delrels;
+	int			ndelrels;
 	int			i;
 
 	/*
@@ -1169,10 +1173,10 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
 	bufptr = buf + MAXALIGN(sizeof(TwoPhaseFileHeader));
 	children = (TransactionId *) bufptr;
 	bufptr += MAXALIGN(hdr->nsubxacts * sizeof(TransactionId));
-	commitrels = (RelFileFork *) bufptr;
-	bufptr += MAXALIGN(hdr->ncommitrels * sizeof(RelFileFork));
-	abortrels = (RelFileFork *) bufptr;
-	bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileFork));
+	commitrels = (RelFileNode *) bufptr;
+	bufptr += MAXALIGN(hdr->ncommitrels * sizeof(RelFileNode));
+	abortrels = (RelFileNode *) bufptr;
+	bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileNode));
 
 	/* compute latestXid among all children */
 	latestXid = TransactionIdLatest(xid, hdr->nsubxacts, children);
@@ -1214,21 +1218,28 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
 	 */
 	if (isCommit)
 	{
-		for (i = 0; i < hdr->ncommitrels; i++)
-		{
-			SMgrRelation srel = smgropen(commitrels[i].rnode);
-			smgrdounlink(srel, commitrels[i].forknum, false, false);
-			smgrclose(srel);
-		}
+		delrels = commitrels;
+		ndelrels = hdr->ncommitrels;
 	}
 	else
 	{
-		for (i = 0; i < hdr->nabortrels; i++)
+		delrels = abortrels;
+		ndelrels = hdr->nabortrels;
+	}
+	for (i = 0; i < ndelrels; i++)
+	{
+		SMgrRelation srel = smgropen(delrels[i]);
+		ForkNumber	fork;
+
+		for (fork = 0; fork <= MAX_FORKNUM; fork++)
 		{
-			SMgrRelation srel = smgropen(abortrels[i].rnode);
-			smgrdounlink(srel, abortrels[i].forknum, false, false);
-			smgrclose(srel);
+			if (smgrexists(srel, fork))
+			{
+				XLogDropRelation(delrels[i], fork);
+				smgrdounlink(srel, fork, false, true);
+			}
 		}
+		smgrclose(srel);
 	}
 
 	/* And now do the callbacks */
@@ -1639,8 +1650,8 @@ RecoverPreparedTransactions(void)
 			bufptr = buf + MAXALIGN(sizeof(TwoPhaseFileHeader));
 			subxids = (TransactionId *) bufptr;
 			bufptr += MAXALIGN(hdr->nsubxacts * sizeof(TransactionId));
-			bufptr += MAXALIGN(hdr->ncommitrels * sizeof(RelFileFork));
-			bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileFork));
+			bufptr += MAXALIGN(hdr->ncommitrels * sizeof(RelFileNode));
+			bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileNode));
 
 			/*
 			 * Reconstruct subtrans state for the transaction --- needed
@@ -1693,7 +1704,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
 								int nchildren,
 								TransactionId *children,
 								int nrels,
-								RelFileFork *rels)
+								RelFileNode *rels)
 {
 	XLogRecData rdata[3];
 	int			lastrdata = 0;
@@ -1718,7 +1729,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
 	{
 		rdata[0].next = &(rdata[1]);
 		rdata[1].data = (char *) rels;
-		rdata[1].len = nrels * sizeof(RelFileFork);
+		rdata[1].len = nrels * sizeof(RelFileNode);
 		rdata[1].buffer = InvalidBuffer;
 		lastrdata = 1;
 	}
@@ -1766,7 +1777,7 @@ RecordTransactionAbortPrepared(TransactionId xid,
 							   int nchildren,
 							   TransactionId *children,
 							   int nrels,
-							   RelFileFork *rels)
+							   RelFileNode *rels)
 {
 	XLogRecData rdata[3];
 	int			lastrdata = 0;
@@ -1796,7 +1807,7 @@ RecordTransactionAbortPrepared(TransactionId xid,
 	{
 		rdata[0].next = &(rdata[1]);
 		rdata[1].data = (char *) rels;
-		rdata[1].len = nrels * sizeof(RelFileFork);
+		rdata[1].len = nrels * sizeof(RelFileNode);
 		rdata[1].buffer = InvalidBuffer;
 		lastrdata = 1;
 	}
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 3d51e35768d..b61fe41083f 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.268 2008/11/11 14:17:01 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.269 2008/11/19 10:34:50 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,6 +28,7 @@
 #include "access/xlogutils.h"
 #include "catalog/catalog.h"
 #include "catalog/namespace.h"
+#include "catalog/storage.h"
 #include "commands/async.h"
 #include "commands/tablecmds.h"
 #include "commands/trigger.h"
@@ -819,7 +820,7 @@ RecordTransactionCommit(void)
 	bool		markXidCommitted = TransactionIdIsValid(xid);
 	TransactionId latestXid = InvalidTransactionId;
 	int			nrels;
-	RelFileFork *rels;
+	RelFileNode *rels;
 	bool		haveNonTemp;
 	int			nchildren;
 	TransactionId *children;
@@ -900,7 +901,7 @@ RecordTransactionCommit(void)
 		{
 			rdata[0].next = &(rdata[1]);
 			rdata[1].data = (char *) rels;
-			rdata[1].len = nrels * sizeof(RelFileFork);
+			rdata[1].len = nrels * sizeof(RelFileNode);
 			rdata[1].buffer = InvalidBuffer;
 			lastrdata = 1;
 		}
@@ -1165,7 +1166,7 @@ RecordTransactionAbort(bool isSubXact)
 	TransactionId xid = GetCurrentTransactionIdIfAny();
 	TransactionId latestXid;
 	int			nrels;
-	RelFileFork *rels;
+	RelFileNode *rels;
 	int			nchildren;
 	TransactionId *children;
 	XLogRecData rdata[3];
@@ -1226,7 +1227,7 @@ RecordTransactionAbort(bool isSubXact)
 	{
 		rdata[0].next = &(rdata[1]);
 		rdata[1].data = (char *) rels;
-		rdata[1].len = nrels * sizeof(RelFileFork);
+		rdata[1].len = nrels * sizeof(RelFileNode);
 		rdata[1].buffer = InvalidBuffer;
 		lastrdata = 1;
 	}
@@ -2078,7 +2079,6 @@ AbortTransaction(void)
 	AtEOXact_xml();
 	AtEOXact_on_commit_actions(false);
 	AtEOXact_Namespace(false);
-	smgrabort();
 	AtEOXact_Files();
 	AtEOXact_ComboCid();
 	AtEOXact_HashTables(false);
@@ -4239,12 +4239,17 @@ xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid)
 	/* Make sure files supposed to be dropped are dropped */
 	for (i = 0; i < xlrec->nrels; i++)
 	{
-		SMgrRelation srel;
+		SMgrRelation srel = smgropen(xlrec->xnodes[i]);
+		ForkNumber fork;
 
-		XLogDropRelation(xlrec->xnodes[i].rnode, xlrec->xnodes[i].forknum);
-
-		srel = smgropen(xlrec->xnodes[i].rnode);
-		smgrdounlink(srel, xlrec->xnodes[i].forknum, false, true);
+		for (fork = 0; fork <= MAX_FORKNUM; fork++)
+		{
+			if (smgrexists(srel, fork))
+			{
+				XLogDropRelation(xlrec->xnodes[i], fork);
+				smgrdounlink(srel, fork, false, true);
+			}
+		}
 		smgrclose(srel);
 	}
 }
@@ -4277,12 +4282,17 @@ xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid)
 	/* Make sure files supposed to be dropped are dropped */
 	for (i = 0; i < xlrec->nrels; i++)
 	{
-		SMgrRelation srel;
+		SMgrRelation srel = smgropen(xlrec->xnodes[i]);
+		ForkNumber fork;
 
-		XLogDropRelation(xlrec->xnodes[i].rnode, xlrec->xnodes[i].forknum);
-
-		srel = smgropen(xlrec->xnodes[i].rnode);
-		smgrdounlink(srel, xlrec->xnodes[i].forknum, false, true);
+		for (fork = 0; fork <= MAX_FORKNUM; fork++)
+		{
+			if (smgrexists(srel, fork))
+			{
+				XLogDropRelation(xlrec->xnodes[i], fork);
+				smgrdounlink(srel, fork, false, true);
+			}
+		}
 		smgrclose(srel);
 	}
 }
@@ -4339,8 +4349,7 @@ xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
 		appendStringInfo(buf, "; rels:");
 		for (i = 0; i < xlrec->nrels; i++)
 		{
-			char *path = relpath(xlrec->xnodes[i].rnode,
-								 xlrec->xnodes[i].forknum);
+			char *path = relpath(xlrec->xnodes[i], MAIN_FORKNUM);
 			appendStringInfo(buf, " %s", path);
 			pfree(path);
 		}
@@ -4367,8 +4376,7 @@ xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
 		appendStringInfo(buf, "; rels:");
 		for (i = 0; i < xlrec->nrels; i++)
 		{
-			char *path = relpath(xlrec->xnodes[i].rnode,
-								 xlrec->xnodes[i].forknum);
+			char *path = relpath(xlrec->xnodes[i], MAIN_FORKNUM);
 			appendStringInfo(buf, " %s", path);
 			pfree(path);
 		}
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index baf0878bede..b481a5ef1d4 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.62 2008/11/11 13:19:16 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.63 2008/11/19 10:34:50 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -273,7 +273,7 @@ XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum,
 	 * filesystem loses an inode during a crash.  Better to write the data
 	 * until we are actually told to delete the file.)
 	 */
-	smgrcreate(smgr, forknum, false, true);
+	smgrcreate(smgr, forknum, true);
 
 	lastblock = smgrnblocks(smgr, forknum);
 
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 9023c795ec1..bb4c42135c5 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -2,7 +2,7 @@
 #
 # Makefile for backend/catalog
 #
-# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.66 2008/02/19 10:30:07 petere Exp $
+# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.67 2008/11/19 10:34:51 heikki Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -13,7 +13,7 @@ include $(top_builddir)/src/Makefile.global
 OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
        pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
        pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
-       pg_type.o toasting.o
+       pg_type.o storage.o toasting.o
 
 BKIFILES = postgres.bki postgres.description postgres.shdescription
 
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index bb5b263ee63..769b3b63575 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.344 2008/11/14 01:57:41 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.345 2008/11/19 10:34:51 heikki Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -47,6 +47,7 @@
 #include "catalog/pg_tablespace.h"
 #include "catalog/pg_type.h"
 #include "catalog/pg_type_fn.h"
+#include "catalog/storage.h"
 #include "commands/tablecmds.h"
 #include "commands/typecmds.h"
 #include "miscadmin.h"
@@ -295,22 +296,13 @@ heap_create(const char *relname,
 	/*
 	 * Have the storage manager create the relation's disk file, if needed.
 	 *
-	 * We create storage for the main fork here, and also for the FSM for a
-	 * heap or toast relation. The caller is responsible for creating any
-	 * additional forks if needed.
+	 * We only create the main fork here, other forks will be created on
+	 * demand.
 	 */
 	if (create_storage)
 	{
-		Assert(rel->rd_smgr == NULL);
 		RelationOpenSmgr(rel);
-		smgrcreate(rel->rd_smgr, MAIN_FORKNUM, rel->rd_istemp, false);
-
-		/*
-		 * For a real heap, create FSM fork as well. Indexams are
-		 * responsible for creating any extra forks themselves.
-		 */
-		if (relkind == RELKIND_RELATION || relkind == RELKIND_TOASTVALUE)
-			smgrcreate(rel->rd_smgr, FSM_FORKNUM, rel->rd_istemp, false);
+		RelationCreateStorage(rel->rd_node, rel->rd_istemp);
 	}
 
 	return rel;
@@ -1426,13 +1418,7 @@ heap_drop_with_catalog(Oid relid)
 	if (rel->rd_rel->relkind != RELKIND_VIEW &&
 		rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)
 	{
-		ForkNumber forknum;
-
-		RelationOpenSmgr(rel);
-		for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
-			if (smgrexists(rel->rd_smgr, forknum))
-				smgrscheduleunlink(rel->rd_smgr, forknum, rel->rd_istemp);
-		RelationCloseSmgr(rel);
+		RelationDropStorage(rel);
 	}
 
 	/*
@@ -2348,7 +2334,6 @@ heap_truncate(List *relids)
 		Relation	rel = lfirst(cell);
 
 		/* Truncate the FSM and actual file (and discard buffers) */
-		FreeSpaceMapTruncateRel(rel, 0);
 		RelationTruncate(rel, 0);
 
 		/* If this relation has indexes, truncate the indexes too */
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index a278d90c2b3..108241be99f 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.309 2008/11/14 01:57:41 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.310 2008/11/19 10:34:51 heikki Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -41,6 +41,7 @@
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_tablespace.h"
 #include "catalog/pg_type.h"
+#include "catalog/storage.h"
 #include "commands/tablecmds.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
@@ -897,7 +898,6 @@ index_drop(Oid indexId)
 	Relation	indexRelation;
 	HeapTuple	tuple;
 	bool		hasexprs;
-	ForkNumber	forknum;
 
 	/*
 	 * To drop an index safely, we must grab exclusive lock on its parent
@@ -918,12 +918,7 @@ index_drop(Oid indexId)
 	/*
 	 * Schedule physical removal of the files
 	 */
-	RelationOpenSmgr(userIndexRelation);
-	for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
-		if (smgrexists(userIndexRelation->rd_smgr, forknum))
-			smgrscheduleunlink(userIndexRelation->rd_smgr, forknum,
-							   userIndexRelation->rd_istemp);
-	RelationCloseSmgr(userIndexRelation);
+	RelationDropStorage(userIndexRelation);
 
 	/*
 	 * Close and flush the index's relcache entry, to ensure relcache doesn't
@@ -1283,11 +1278,9 @@ setNewRelfilenode(Relation relation, TransactionId freezeXid)
 {
 	Oid			newrelfilenode;
 	RelFileNode newrnode;
-	SMgrRelation srel;
 	Relation	pg_class;
 	HeapTuple	tuple;
 	Form_pg_class rd_rel;
-	ForkNumber	i;
 
 	/* Can't change relfilenode for nailed tables (indexes ok though) */
 	Assert(!relation->rd_isnailed ||
@@ -1318,8 +1311,6 @@ setNewRelfilenode(Relation relation, TransactionId freezeXid)
 			 RelationGetRelid(relation));
 	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
 
-	RelationOpenSmgr(relation);
-
 	/*
 	 * ... and create storage for corresponding forks in the new relfilenode.
 	 *
@@ -1327,28 +1318,14 @@ setNewRelfilenode(Relation relation, TransactionId freezeXid)
 	 */
 	newrnode = relation->rd_node;
 	newrnode.relNode = newrelfilenode;
-	srel = smgropen(newrnode);
-
-	/* Create the main fork, like heap_create() does */
-	smgrcreate(srel, MAIN_FORKNUM, relation->rd_istemp, false);
 
 	/*
-	 * For a heap, create FSM fork as well. Indexams are responsible for
-	 * creating any extra forks themselves.
+	 * Create the main fork, like heap_create() does, and drop the old
+	 * storage.
 	 */
-	if (relation->rd_rel->relkind == RELKIND_RELATION ||
-		relation->rd_rel->relkind == RELKIND_TOASTVALUE)
-		smgrcreate(srel, FSM_FORKNUM, relation->rd_istemp, false);
-
-	/* schedule unlinking old files */
-	for (i = 0; i <= MAX_FORKNUM; i++)
-	{
-		if (smgrexists(relation->rd_smgr, i))
-			smgrscheduleunlink(relation->rd_smgr, i, relation->rd_istemp);
-	}
-
-	smgrclose(srel);
-	RelationCloseSmgr(relation);
+	RelationCreateStorage(newrnode, relation->rd_istemp);
+	smgrclosenode(newrnode);
+	RelationDropStorage(relation);
 
 	/* update the pg_class row */
 	rd_rel->relfilenode = newrelfilenode;
@@ -2326,8 +2303,7 @@ reindex_index(Oid indexId)
 		if (inplace)
 		{
 			/*
-			 * Truncate the actual file (and discard buffers). The indexam
-			 * is responsible for truncating the FSM, if applicable
+			 * Truncate the actual file (and discard buffers).
 			 */
 			RelationTruncate(iRel, 0);
 		}
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
new file mode 100644
index 00000000000..c8187d511c9
--- /dev/null
+++ b/src/backend/catalog/storage.c
@@ -0,0 +1,462 @@
+/*-------------------------------------------------------------------------
+ *
+ * storage.c
+ *	  code to create and destroy physical storage for relations
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  $PostgreSQL: pgsql/src/backend/catalog/storage.c,v 1.1 2008/11/19 10:34:51 heikki Exp $
+ *
+ * NOTES
+ *	  Some of this code used to be in storage/smgr/smgr.c, and the
+ *	  function names still reflect that.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/xact.h"
+#include "access/xlogutils.h"
+#include "catalog/catalog.h"
+#include "catalog/storage.h"
+#include "storage/freespace.h"
+#include "storage/smgr.h"
+#include "utils/memutils.h"
+#include "utils/rel.h"
+
+/*
+ * We keep a list of all relations (represented as RelFileNode values)
+ * that have been created or deleted in the current transaction.  When
+ * a relation is created, we create the physical file immediately, but
+ * remember it so that we can delete the file again if the current
+ * transaction is aborted.	Conversely, a deletion request is NOT
+ * executed immediately, but is just entered in the list.  When and if
+ * the transaction commits, we can delete the physical file.
+ *
+ * To handle subtransactions, every entry is marked with its transaction
+ * nesting level.  At subtransaction commit, we reassign the subtransaction's
+ * entries to the parent nesting level.  At subtransaction abort, we can
+ * immediately execute the abort-time actions for all entries of the current
+ * nesting level.
+ *
+ * NOTE: the list is kept in TopMemoryContext to be sure it won't disappear
+ * unbetimes.  It'd probably be OK to keep it in TopTransactionContext,
+ * but I'm being paranoid.
+ */
+
+typedef struct PendingRelDelete
+{
+	RelFileNode relnode;		/* relation that may need to be deleted */
+	bool		isTemp;			/* is it a temporary relation? */
+	bool		atCommit;		/* T=delete at commit; F=delete at abort */
+	int			nestLevel;		/* xact nesting level of request */
+	struct PendingRelDelete *next;		/* linked-list link */
+} PendingRelDelete;
+
+static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
+
+/*
+ * Declarations for smgr-related XLOG records
+ *
+ * Note: we log file creation and truncation here, but logging of deletion
+ * actions is handled by xact.c, because it is part of transaction commit.
+ */
+
+/* XLOG gives us high 4 bits */
+#define XLOG_SMGR_CREATE	0x10
+#define XLOG_SMGR_TRUNCATE	0x20
+
+typedef struct xl_smgr_create
+{
+	RelFileNode rnode;
+} xl_smgr_create;
+
+typedef struct xl_smgr_truncate
+{
+	BlockNumber blkno;
+	RelFileNode rnode;
+} xl_smgr_truncate;
+
+
+/*
+ * RelationCreateStorage
+ *		Create physical storage for a relation.
+ *
+ * Create the underlying disk file storage for the relation. This only
+ * creates the main fork; additional forks are created lazily by the
+ * modules that need them.
+ *
+ * This function is transactional. The creation is WAL-logged, and if the
+ * transaction aborts later on, the storage will be destroyed.
+ */
+void
+RelationCreateStorage(RelFileNode rnode, bool istemp)
+{
+	PendingRelDelete *pending;
+	XLogRecPtr	lsn;
+	XLogRecData rdata;
+	xl_smgr_create xlrec;
+	SMgrRelation srel;
+
+	srel = smgropen(rnode);
+	smgrcreate(srel, MAIN_FORKNUM, false);
+
+	if (istemp)
+	{
+		/*
+		 * Make an XLOG entry showing the file creation.  If we abort, the file
+		 * will be dropped at abort time.
+		 */
+		xlrec.rnode = rnode;
+
+		rdata.data = (char *) &xlrec;
+		rdata.len = sizeof(xlrec);
+		rdata.buffer = InvalidBuffer;
+		rdata.next = NULL;
+
+		lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE, &rdata);
+	}
+
+	/* Add the relation to the list of stuff to delete at abort */
+	pending = (PendingRelDelete *)
+		MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
+	pending->relnode = rnode;
+	pending->isTemp = istemp;
+	pending->atCommit = false;	/* delete if abort */
+	pending->nestLevel = GetCurrentTransactionNestLevel();
+	pending->next = pendingDeletes;
+	pendingDeletes = pending;
+}
+
+/*
+ * RelationDropStorage
+ *		Schedule unlinking of physical storage at transaction commit.
+ */
+void
+RelationDropStorage(Relation rel)
+{
+	PendingRelDelete *pending;
+
+	/* Add the relation to the list of stuff to delete at commit */
+	pending = (PendingRelDelete *)
+		MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
+	pending->relnode = rel->rd_node;
+	pending->isTemp = rel->rd_istemp;
+	pending->atCommit = true;	/* delete if commit */
+	pending->nestLevel = GetCurrentTransactionNestLevel();
+	pending->next = pendingDeletes;
+	pendingDeletes = pending;
+
+	/*
+	 * NOTE: if the relation was created in this transaction, it will now be
+	 * present in the pending-delete list twice, once with atCommit true and
+	 * once with atCommit false.  Hence, it will be physically deleted at end
+	 * of xact in either case (and the other entry will be ignored by
+	 * smgrDoPendingDeletes, so no error will occur).  We could instead remove
+	 * the existing list entry and delete the physical file immediately, but
+	 * for now I'll keep the logic simple.
+	 */
+
+	RelationCloseSmgr(rel);
+}
+
+/*
+ * RelationTruncate
+ *		Physically truncate a relation to the specified number of blocks.
+ *
+ * This includes getting rid of any buffers for the blocks that are to be
+ * dropped. If 'fsm' is true, the FSM of the relation is truncated as well.
+ */
+void
+RelationTruncate(Relation rel, BlockNumber nblocks)
+{
+	bool fsm;
+
+	/* Open it at the smgr level if not already done */
+	RelationOpenSmgr(rel);
+
+	/* Make sure rd_targblock isn't pointing somewhere past end */
+	rel->rd_targblock = InvalidBlockNumber;
+
+	/* Truncate the FSM first if it exists */
+	fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM);
+	if (fsm)
+		FreeSpaceMapTruncateRel(rel, nblocks);
+
+	/*
+	 * We WAL-log the truncation before actually truncating, which
+	 * means trouble if the truncation fails. If we then crash, the WAL
+	 * replay likely isn't going to succeed in the truncation either, and
+	 * cause a PANIC. It's tempting to put a critical section here, but
+	 * that cure would be worse than the disease. It would turn a usually
+	 * harmless failure to truncate, that could spell trouble at WAL replay,
+	 * into a certain PANIC.
+	 */
+	if (rel->rd_istemp)
+	{
+		/*
+		 * Make an XLOG entry showing the file truncation.
+		 */
+		XLogRecPtr	lsn;
+		XLogRecData rdata;
+		xl_smgr_truncate xlrec;
+
+		xlrec.blkno = nblocks;
+		xlrec.rnode = rel->rd_node;
+
+		rdata.data = (char *) &xlrec;
+		rdata.len = sizeof(xlrec);
+		rdata.buffer = InvalidBuffer;
+		rdata.next = NULL;
+
+		lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE, &rdata);
+
+		/*
+		 * Flush, because otherwise the truncation of the main relation
+		 * might hit the disk before the WAL record of truncating the
+		 * FSM is flushed. If we crashed during that window, we'd be
+		 * left with a truncated heap, but the FSM would still contain
+		 * entries for the non-existent heap pages.
+		 */
+		if (fsm)
+			XLogFlush(lsn);
+	}
+
+	/* Do the real work */
+	smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks, rel->rd_istemp);
+}
+
+/*
+ *	smgrDoPendingDeletes() -- Take care of relation deletes at end of xact.
+ *
+ * This also runs when aborting a subxact; we want to clean up a failed
+ * subxact immediately.
+ */
+void
+smgrDoPendingDeletes(bool isCommit)
+{
+	int			nestLevel = GetCurrentTransactionNestLevel();
+	PendingRelDelete *pending;
+	PendingRelDelete *prev;
+	PendingRelDelete *next;
+
+	prev = NULL;
+	for (pending = pendingDeletes; pending != NULL; pending = next)
+	{
+		next = pending->next;
+		if (pending->nestLevel < nestLevel)
+		{
+			/* outer-level entries should not be processed yet */
+			prev = pending;
+		}
+		else
+		{
+			/* unlink list entry first, so we don't retry on failure */
+			if (prev)
+				prev->next = next;
+			else
+				pendingDeletes = next;
+			/* do deletion if called for */
+			if (pending->atCommit == isCommit)
+			{
+				int i;
+
+				/* schedule unlinking old files */
+				SMgrRelation srel;
+
+				srel = smgropen(pending->relnode);
+				for (i = 0; i <= MAX_FORKNUM; i++)
+				{
+					if (smgrexists(srel, i))
+						smgrdounlink(srel,
+									 i,
+									 pending->isTemp,
+									 false);
+				}
+				smgrclose(srel);
+			}
+			/* must explicitly free the list entry */
+			pfree(pending);
+			/* prev does not change */
+		}
+	}
+}
+
+/*
+ * smgrGetPendingDeletes() -- Get a list of relations to be deleted.
+ *
+ * The return value is the number of relations scheduled for termination.
+ * *ptr is set to point to a freshly-palloc'd array of RelFileNodes.
+ * If there are no relations to be deleted, *ptr is set to NULL.
+ *
+ * If haveNonTemp isn't NULL, the bool it points to gets set to true if
+ * there is any non-temp table pending to be deleted; false if not.
+ *
+ * Note that the list does not include anything scheduled for termination
+ * by upper-level transactions.
+ */
+int
+smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr, bool *haveNonTemp)
+{
+	int			nestLevel = GetCurrentTransactionNestLevel();
+	int			nrels;
+	RelFileNode *rptr;
+	PendingRelDelete *pending;
+
+	nrels = 0;
+	if (haveNonTemp)
+		*haveNonTemp = false;
+	for (pending = pendingDeletes; pending != NULL; pending = pending->next)
+	{
+		if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
+			nrels++;
+	}
+	if (nrels == 0)
+	{
+		*ptr = NULL;
+		return 0;
+	}
+	rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
+	*ptr = rptr;
+	for (pending = pendingDeletes; pending != NULL; pending = pending->next)
+	{
+		if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
+		{
+			*rptr = pending->relnode;
+			rptr++;
+		}
+		if (haveNonTemp && !pending->isTemp)
+			*haveNonTemp = true;
+	}
+	return nrels;
+}
+
+/*
+ *	PostPrepare_smgr -- Clean up after a successful PREPARE
+ *
+ * What we have to do here is throw away the in-memory state about pending
+ * relation deletes.  It's all been recorded in the 2PC state file and
+ * it's no longer smgr's job to worry about it.
+ */
+void
+PostPrepare_smgr(void)
+{
+	PendingRelDelete *pending;
+	PendingRelDelete *next;
+
+	for (pending = pendingDeletes; pending != NULL; pending = next)
+	{
+		next = pending->next;
+		pendingDeletes = next;
+		/* must explicitly free the list entry */
+		pfree(pending);
+	}
+}
+
+
+/*
+ * AtSubCommit_smgr() --- Take care of subtransaction commit.
+ *
+ * Reassign all items in the pending-deletes list to the parent transaction.
+ */
+void
+AtSubCommit_smgr(void)
+{
+	int			nestLevel = GetCurrentTransactionNestLevel();
+	PendingRelDelete *pending;
+
+	for (pending = pendingDeletes; pending != NULL; pending = pending->next)
+	{
+		if (pending->nestLevel >= nestLevel)
+			pending->nestLevel = nestLevel - 1;
+	}
+}
+
+/*
+ * AtSubAbort_smgr() --- Take care of subtransaction abort.
+ *
+ * Delete created relations and forget about deleted relations.
+ * We can execute these operations immediately because we know this
+ * subtransaction will not commit.
+ */
+void
+AtSubAbort_smgr(void)
+{
+	smgrDoPendingDeletes(false);
+}
+
+void
+smgr_redo(XLogRecPtr lsn, XLogRecord *record)
+{
+	uint8		info = record->xl_info & ~XLR_INFO_MASK;
+
+	if (info == XLOG_SMGR_CREATE)
+	{
+		xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record);
+		SMgrRelation reln;
+
+		reln = smgropen(xlrec->rnode);
+		smgrcreate(reln, MAIN_FORKNUM, true);
+	}
+	else if (info == XLOG_SMGR_TRUNCATE)
+	{
+		xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
+		SMgrRelation reln;
+
+		reln = smgropen(xlrec->rnode);
+
+		/*
+		 * Forcibly create relation if it doesn't exist (which suggests that
+		 * it was dropped somewhere later in the WAL sequence).  As in
+		 * XLogOpenRelation, we prefer to recreate the rel and replay the log
+		 * as best we can until the drop is seen.
+		 */
+		smgrcreate(reln, MAIN_FORKNUM, true);
+
+		smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno, false);
+
+		/* Also tell xlogutils.c about it */
+		XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
+ 
+		/* Truncate FSM too */
+		if (smgrexists(reln, FSM_FORKNUM))
+		{
+			Relation rel = CreateFakeRelcacheEntry(xlrec->rnode);
+			FreeSpaceMapTruncateRel(rel, xlrec->blkno);
+			FreeFakeRelcacheEntry(rel);
+		}
+
+	}
+	else
+		elog(PANIC, "smgr_redo: unknown op code %u", info);
+}
+
+void
+smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
+{
+	uint8		info = xl_info & ~XLR_INFO_MASK;
+
+	if (info == XLOG_SMGR_CREATE)
+	{
+		xl_smgr_create *xlrec = (xl_smgr_create *) rec;
+		char *path = relpath(xlrec->rnode, MAIN_FORKNUM);
+
+		appendStringInfo(buf, "file create: %s", path);
+		pfree(path);
+	}
+	else if (info == XLOG_SMGR_TRUNCATE)
+	{
+		xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
+		char *path = relpath(xlrec->rnode, MAIN_FORKNUM);
+
+		appendStringInfo(buf, "file truncate: %s to %u blocks", path,
+						 xlrec->blkno);
+		pfree(path);
+	}
+	else
+		appendStringInfo(buf, "UNKNOWN");
+}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 2af083fd136..d252632ee7e 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.270 2008/11/14 01:57:41 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.271 2008/11/19 10:34:51 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,6 +35,7 @@
 #include "catalog/pg_trigger.h"
 #include "catalog/pg_type.h"
 #include "catalog/pg_type_fn.h"
+#include "catalog/storage.h"
 #include "catalog/toasting.h"
 #include "commands/cluster.h"
 #include "commands/defrem.h"
@@ -6567,22 +6568,26 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace)
 	 * of old physical files.
 	 *
 	 * NOTE: any conflict in relfilenode value will be caught in
-	 *		 smgrcreate() below.
+	 *		 RelationCreateStorage().
 	 */
-	for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
+	RelationCreateStorage(newrnode, rel->rd_istemp);
+
+	/* copy main fork */
+	copy_relation_data(rel->rd_smgr, dstrel, MAIN_FORKNUM, rel->rd_istemp);
+
+	/* copy those extra forks that exist */
+	for (forkNum = MAIN_FORKNUM + 1; forkNum <= MAX_FORKNUM; forkNum++)
 	{
 		if (smgrexists(rel->rd_smgr, forkNum))
 		{
-			smgrcreate(dstrel, forkNum, rel->rd_istemp, false);
+			smgrcreate(dstrel, forkNum, false);
 			copy_relation_data(rel->rd_smgr, dstrel, forkNum, rel->rd_istemp);
-
-			smgrscheduleunlink(rel->rd_smgr, forkNum, rel->rd_istemp);
 		}
 	}
 
-	/* Close old and new relation */
+	/* drop old relation, and close new one */
+	RelationDropStorage(rel);
 	smgrclose(dstrel);
-	RelationCloseSmgr(rel);
 
 	/* update the pg_class row */
 	rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index aa4c18915a2..9cb641fe3fd 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.380 2008/11/10 00:49:37 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.381 2008/11/19 10:34:51 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,6 +31,7 @@
 #include "catalog/namespace.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_namespace.h"
+#include "catalog/storage.h"
 #include "commands/dbcommands.h"
 #include "commands/vacuum.h"
 #include "executor/executor.h"
@@ -2863,7 +2864,6 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
 	/* Truncate relation, if needed */
 	if (blkno < nblocks)
 	{
-		FreeSpaceMapTruncateRel(onerel, blkno);
 		RelationTruncate(onerel, blkno);
 		vacrelstats->rel_pages = blkno; /* set new number of blocks */
 	}
@@ -3258,7 +3258,6 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages)
 				(errmsg("\"%s\": truncated %u to %u pages",
 						RelationGetRelationName(onerel),
 						vacrelstats->rel_pages, relblocks)));
-		FreeSpaceMapTruncateRel(onerel, relblocks);
 		RelationTruncate(onerel, relblocks);
 		vacrelstats->rel_pages = relblocks;		/* set new number of blocks */
 	}
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index 246962a414a..4230b2e3ef2 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -29,7 +29,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.110 2008/11/10 00:49:37 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.111 2008/11/19 10:34:51 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,6 +40,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/transam.h"
+#include "catalog/storage.h"
 #include "commands/dbcommands.h"
 #include "commands/vacuum.h"
 #include "miscadmin.h"
@@ -827,7 +828,6 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
 	/*
 	 * Okay to truncate.
 	 */
-	FreeSpaceMapTruncateRel(onerel, new_rel_pages);
 	RelationTruncate(onerel, new_rel_pages);
 
 	/*
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 6212add6bcb..2df21b5e355 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.132 2008/11/09 21:24:32 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.133 2008/11/19 10:34:52 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,13 +19,13 @@
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_rewrite.h"
+#include "catalog/storage.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/parse_utilcmd.h"
 #include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteManip.h"
 #include "rewrite/rewriteSupport.h"
-#include "storage/smgr.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/inval.h"
@@ -484,16 +484,7 @@ DefineQueryRewrite(char *rulename,
 	 * XXX what about getting rid of its TOAST table?  For now, we don't.
 	 */
 	if (RelisBecomingView)
-	{
-		ForkNumber forknum;
-
-		RelationOpenSmgr(event_relation);
-		for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
-			if (smgrexists(event_relation->rd_smgr, forknum))
-				smgrscheduleunlink(event_relation->rd_smgr, forknum,
-								   event_relation->rd_istemp);
-		RelationCloseSmgr(event_relation);
-	}
+		RelationDropStorage(event_relation);
 
 	/* Close rel, but keep lock till commit... */
 	heap_close(event_relation, NoLock);
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index bb4b968f1c4..b7e0861e2b5 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.241 2008/11/11 13:19:16 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.242 2008/11/19 10:34:52 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1695,8 +1695,6 @@ void
 BufmgrCommit(void)
 {
 	/* Nothing to do in bufmgr anymore... */
-
-	smgrcommit();
 }
 
 /*
@@ -1848,26 +1846,6 @@ RelationGetNumberOfBlocks(Relation relation)
 	return smgrnblocks(relation->rd_smgr, MAIN_FORKNUM);
 }
 
-/*
- * RelationTruncate
- *		Physically truncate a relation to the specified number of blocks.
- *
- * As of Postgres 8.1, this includes getting rid of any buffers for the
- * blocks that are to be dropped; previously, callers had to do that.
- */
-void
-RelationTruncate(Relation rel, BlockNumber nblocks)
-{
-	/* Open it at the smgr level if not already done */
-	RelationOpenSmgr(rel);
-
-	/* Make sure rd_targblock isn't pointing somewhere past end */
-	rel->rd_targblock = InvalidBlockNumber;
-
-	/* Do the real work */
-	smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks, rel->rd_istemp);
-}
-
 /* ---------------------------------------------------------------------
  *		DropRelFileNodeBuffers
  *
diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c
index 10cca029d10..013b4ce2211 100644
--- a/src/backend/storage/freespace/freespace.c
+++ b/src/backend/storage/freespace/freespace.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.66 2008/10/31 19:40:27 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.67 2008/11/19 10:34:52 heikki Exp $
  *
  *
  * NOTES:
@@ -47,7 +47,7 @@
  * MaxFSMRequestSize depends on the architecture and BLCKSZ, but assuming
  * default 8k BLCKSZ, and that MaxFSMRequestSize is 24 bytes, the categories
  * look like this
- * 
+ *
  *
  * Range     Category
  * 0    - 31   0
@@ -93,15 +93,6 @@ typedef struct
 /* Address of the root page. */
 static const FSMAddress FSM_ROOT_ADDRESS = { FSM_ROOT_LEVEL, 0 };
 
-/* XLOG record types */
-#define XLOG_FSM_TRUNCATE     0x00    /* truncate */
-
-typedef struct
-{
-	RelFileNode node;			/* truncated relation */
-	BlockNumber nheapblocks;	/* new number of blocks in the heap */
-} xl_fsm_truncate;
-
 /* functions to navigate the tree */
 static FSMAddress fsm_get_child(FSMAddress parent, uint16 slot);
 static FSMAddress fsm_get_parent(FSMAddress child, uint16 *slot);
@@ -110,7 +101,7 @@ static BlockNumber fsm_get_heap_blk(FSMAddress addr, uint16 slot);
 static BlockNumber fsm_logical_to_physical(FSMAddress addr);
 
 static Buffer fsm_readbuf(Relation rel, FSMAddress addr, bool extend);
-static void fsm_extend(Relation rel, BlockNumber nfsmblocks);
+static void fsm_extend(Relation rel, BlockNumber nfsmblocks, bool createstorage);
 
 /* functions to convert amount of free space to a FSM category */
 static uint8 fsm_space_avail_to_cat(Size avail);
@@ -123,8 +114,6 @@ static int fsm_set_and_search(Relation rel, FSMAddress addr, uint16 slot,
 static BlockNumber fsm_search(Relation rel, uint8 min_cat);
 static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof);
 
-static void fsm_redo_truncate(xl_fsm_truncate *xlrec);
-
 
 /******** Public API ********/
 
@@ -275,6 +264,13 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
 
 	RelationOpenSmgr(rel);
 
+	/*
+	 * If no FSM has been created yet for this relation, there's nothing to
+	 * truncate.
+	 */
+	if (!smgrexists(rel->rd_smgr, FSM_FORKNUM))
+		return;
+
 	/* Get the location in the FSM of the first removed heap block */
 	first_removed_address = fsm_get_location(nblocks, &first_removed_slot);
 
@@ -306,43 +302,12 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
 	/* Truncate the unused FSM pages */
 	smgrtruncate(rel->rd_smgr, FSM_FORKNUM, new_nfsmblocks, rel->rd_istemp);
 
-	/*
-	 * FSM truncations are WAL-logged, because we must never return a block
-	 * that doesn't exist in the heap, not even if we crash before the FSM
-	 * truncation has made it to disk. smgrtruncate() writes its own WAL
-	 * record, but that's not enough to zero out the last remaining FSM page.
-	 * (if we didn't need to zero out anything above, we can skip this)
-	 */
-	if (!rel->rd_istemp && first_removed_slot != 0)
-	{
-		xl_fsm_truncate xlrec;
-		XLogRecData		rdata;
-		XLogRecPtr		recptr;
-
-		xlrec.node = rel->rd_node;
-		xlrec.nheapblocks = nblocks;
-
-		rdata.data = (char *) &xlrec;
-		rdata.len = sizeof(xl_fsm_truncate);
-		rdata.buffer = InvalidBuffer;
-		rdata.next = NULL;
-
-		recptr = XLogInsert(RM_FREESPACE_ID, XLOG_FSM_TRUNCATE, &rdata);
-
-		/*
-		 * Flush, because otherwise the truncation of the main relation
-		 * might hit the disk before the WAL record of truncating the
-		 * FSM is flushed. If we crashed during that window, we'd be
-		 * left with a truncated heap, without a truncated FSM.
-		 */
-		XLogFlush(recptr);
-	}
-
 	/*
 	 * Need to invalidate the relcache entry, because rd_fsm_nblocks_cache
 	 * seen by other backends is no longer valid.
 	 */
-	CacheInvalidateRelcache(rel);
+	if (!InRecovery)
+		CacheInvalidateRelcache(rel);
 
 	rel->rd_fsm_nblocks_cache = new_nfsmblocks;
 }
@@ -538,14 +503,19 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
 
 	RelationOpenSmgr(rel);
 
-	if (rel->rd_fsm_nblocks_cache == InvalidBlockNumber || 
+	if (rel->rd_fsm_nblocks_cache == InvalidBlockNumber ||
 		rel->rd_fsm_nblocks_cache <= blkno)
-		rel->rd_fsm_nblocks_cache = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
+	{
+		if (!smgrexists(rel->rd_smgr, FSM_FORKNUM))
+			fsm_extend(rel, blkno + 1, true);
+		else
+			rel->rd_fsm_nblocks_cache = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
+	}
 
 	if (blkno >= rel->rd_fsm_nblocks_cache)
 	{
 		if (extend)
-			fsm_extend(rel, blkno + 1);
+			fsm_extend(rel, blkno + 1, false);
 		else
 			return InvalidBuffer;
 	}
@@ -566,10 +536,11 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
 /*
  * Ensure that the FSM fork is at least n_fsmblocks long, extending
  * it if necessary with empty pages. And by empty, I mean pages filled
- * with zeros, meaning there's no free space.
+ * with zeros, meaning there's no free space. If createstorage is true,
+ * the FSM file might need to be created first.
  */
 static void
-fsm_extend(Relation rel, BlockNumber n_fsmblocks)
+fsm_extend(Relation rel, BlockNumber n_fsmblocks, bool createstorage)
 {
 	BlockNumber n_fsmblocks_now;
 	Page pg;
@@ -589,7 +560,15 @@ fsm_extend(Relation rel, BlockNumber n_fsmblocks)
 	 */
 	LockRelationForExtension(rel, ExclusiveLock);
 
-	n_fsmblocks_now = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
+	/* Create the FSM file first if it doesn't exist */
+	if (createstorage && !smgrexists(rel->rd_smgr, FSM_FORKNUM))
+	{
+		smgrcreate(rel->rd_smgr, FSM_FORKNUM, false);
+		n_fsmblocks_now = 0;
+	}
+	else
+		n_fsmblocks_now = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
+
 	while (n_fsmblocks_now < n_fsmblocks)
 	{
 		smgrextend(rel->rd_smgr, FSM_FORKNUM, n_fsmblocks_now,
@@ -799,75 +778,3 @@ fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof_p)
 
 	return max_avail;
 }
-
-
-/****** WAL-logging ******/
-
-static void
-fsm_redo_truncate(xl_fsm_truncate *xlrec)
-{
-	FSMAddress	first_removed_address;
-	uint16		first_removed_slot;
-	BlockNumber fsmblk;
-	Buffer		buf;
-
-	/* Get the location in the FSM of the first removed heap block */
-	first_removed_address = fsm_get_location(xlrec->nheapblocks,
-											 &first_removed_slot);
-	fsmblk = fsm_logical_to_physical(first_removed_address);
-
-	/*
-	 * Zero out the tail of the last remaining FSM page. We rely on the
-	 * replay of the smgr truncation record to remove completely unused
-	 * pages.
-	 */
-	buf = XLogReadBufferExtended(xlrec->node, FSM_FORKNUM, fsmblk,
-								 RBM_ZERO_ON_ERROR);
-	if (BufferIsValid(buf))
-	{
-		Page page = BufferGetPage(buf);
-
-		if (PageIsNew(page))
-			PageInit(page, BLCKSZ, 0);
-		fsm_truncate_avail(page, first_removed_slot);
-		MarkBufferDirty(buf);
-		UnlockReleaseBuffer(buf);
-	}
-}
-
-void
-fsm_redo(XLogRecPtr lsn, XLogRecord *record)
-{
-	uint8		info = record->xl_info & ~XLR_INFO_MASK;
-
-	switch (info)
-	{
-		case XLOG_FSM_TRUNCATE:
-			fsm_redo_truncate((xl_fsm_truncate *) XLogRecGetData(record));
-			break;
-		default:
-			elog(PANIC, "fsm_redo: unknown op code %u", info);
-	}
-}
-
-void
-fsm_desc(StringInfo buf, uint8 xl_info, char *rec)
-{
-	uint8           info = xl_info & ~XLR_INFO_MASK;
-
-	switch (info)
-	{
-		case XLOG_FSM_TRUNCATE:
-		{
-			xl_fsm_truncate *xlrec = (xl_fsm_truncate *) rec;
-
-			appendStringInfo(buf, "truncate: rel %u/%u/%u; nheapblocks %u;",
-							 xlrec->node.spcNode, xlrec->node.dbNode,
-							 xlrec->node.relNode, xlrec->nheapblocks);
-			break;
-		}
-		default:
-			appendStringInfo(buf, "UNKNOWN");
-			break;
-	}
-}
diff --git a/src/backend/storage/freespace/indexfsm.c b/src/backend/storage/freespace/indexfsm.c
index 768b633f081..58d8e6caf2e 100644
--- a/src/backend/storage/freespace/indexfsm.c
+++ b/src/backend/storage/freespace/indexfsm.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/freespace/indexfsm.c,v 1.2 2008/10/06 08:04:11 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/freespace/indexfsm.c,v 1.3 2008/11/19 10:34:52 heikki Exp $
  *
  *
  * NOTES:
@@ -30,20 +30,6 @@
  * Exported routines
  */
 
-/*
- * InitIndexFreeSpaceMap - Create or reset the FSM fork for relation.
- */
-void
-InitIndexFreeSpaceMap(Relation rel)
-{
-	/* Create FSM fork if it doesn't exist yet, or truncate it if it does */
-	RelationOpenSmgr(rel);
-	if (!smgrexists(rel->rd_smgr, FSM_FORKNUM))
-		smgrcreate(rel->rd_smgr, FSM_FORKNUM, rel->rd_istemp, false);
-	else
-		smgrtruncate(rel->rd_smgr, FSM_FORKNUM, 0, rel->rd_istemp);
-}
-
 /*
  * GetFreeIndexPage - return a free page from the FSM
  *
@@ -79,18 +65,6 @@ RecordUsedIndexPage(Relation rel, BlockNumber usedBlock)
 	RecordPageWithFreeSpace(rel, usedBlock, 0);
 }
 
-/*
- * IndexFreeSpaceMapTruncate - adjust for truncation of a relation.
- *
- * We need to delete any stored data past the new relation length, so that
- * we don't bogusly return removed block numbers.
- */
-void
-IndexFreeSpaceMapTruncate(Relation rel, BlockNumber nblocks)
-{
-	FreeSpaceMapTruncateRel(rel, nblocks);
-}
-
 /*
  * IndexFreeSpaceMapVacuum - scan and fix any inconsistencies in the FSM
  */
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index 820d4910408..f6dd2b82214 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -11,13 +11,12 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.113 2008/11/11 13:19:16 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.114 2008/11/19 10:34:52 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
-#include "access/xact.h"
 #include "access/xlogutils.h"
 #include "catalog/catalog.h"
 #include "commands/tablespace.h"
@@ -25,7 +24,6 @@
 #include "storage/ipc.h"
 #include "storage/smgr.h"
 #include "utils/hsearch.h"
-#include "utils/memutils.h"
 
 
 /*
@@ -58,8 +56,6 @@ typedef struct f_smgr
 	void		(*smgr_truncate) (SMgrRelation reln, ForkNumber forknum,
 								  BlockNumber nblocks, bool isTemp);
 	void		(*smgr_immedsync) (SMgrRelation reln, ForkNumber forknum);
-	void		(*smgr_commit) (void);	/* may be NULL */
-	void		(*smgr_abort) (void);	/* may be NULL */
 	void		(*smgr_pre_ckpt) (void);		/* may be NULL */
 	void		(*smgr_sync) (void);	/* may be NULL */
 	void		(*smgr_post_ckpt) (void);		/* may be NULL */
@@ -70,7 +66,7 @@ static const f_smgr smgrsw[] = {
 	/* magnetic disk */
 	{mdinit, NULL, mdclose, mdcreate, mdexists, mdunlink, mdextend,
 		mdread, mdwrite, mdnblocks, mdtruncate, mdimmedsync,
-		NULL, NULL, mdpreckpt, mdsync, mdpostckpt
+		mdpreckpt, mdsync, mdpostckpt
 	}
 };
 
@@ -82,65 +78,6 @@ static const int NSmgr = lengthof(smgrsw);
  */
 static HTAB *SMgrRelationHash = NULL;
 
-/*
- * We keep a list of all relations (represented as RelFileNode values)
- * that have been created or deleted in the current transaction.  When
- * a relation is created, we create the physical file immediately, but
- * remember it so that we can delete the file again if the current
- * transaction is aborted.	Conversely, a deletion request is NOT
- * executed immediately, but is just entered in the list.  When and if
- * the transaction commits, we can delete the physical file.
- *
- * To handle subtransactions, every entry is marked with its transaction
- * nesting level.  At subtransaction commit, we reassign the subtransaction's
- * entries to the parent nesting level.  At subtransaction abort, we can
- * immediately execute the abort-time actions for all entries of the current
- * nesting level.
- *
- * NOTE: the list is kept in TopMemoryContext to be sure it won't disappear
- * unbetimes.  It'd probably be OK to keep it in TopTransactionContext,
- * but I'm being paranoid.
- */
-
-typedef struct PendingRelDelete
-{
-	RelFileNode relnode;		/* relation that may need to be deleted */
-	ForkNumber	forknum;		/* fork number that may need to be deleted */
-	int			which;			/* which storage manager? */
-	bool		isTemp;			/* is it a temporary relation? */
-	bool		atCommit;		/* T=delete at commit; F=delete at abort */
-	int			nestLevel;		/* xact nesting level of request */
-	struct PendingRelDelete *next;		/* linked-list link */
-} PendingRelDelete;
-
-static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
-
-
-/*
- * Declarations for smgr-related XLOG records
- *
- * Note: we log file creation and truncation here, but logging of deletion
- * actions is handled by xact.c, because it is part of transaction commit.
- */
-
-/* XLOG gives us high 4 bits */
-#define XLOG_SMGR_CREATE	0x10
-#define XLOG_SMGR_TRUNCATE	0x20
-
-typedef struct xl_smgr_create
-{
-	RelFileNode rnode;
-	ForkNumber	forknum;
-} xl_smgr_create;
-
-typedef struct xl_smgr_truncate
-{
-	BlockNumber blkno;
-	RelFileNode rnode;
-	ForkNumber forknum;
-} xl_smgr_truncate;
-
-
 /* local function prototypes */
 static void smgrshutdown(int code, Datum arg);
 static void smgr_internal_unlink(RelFileNode rnode, ForkNumber forknum, 
@@ -341,18 +278,11 @@ smgrclosenode(RelFileNode rnode)
  *		to be created.
  *
  *		If isRedo is true, it is okay for the underlying file to exist
- *		already because we are in a WAL replay sequence.  In this case
- *		we should make no PendingRelDelete entry; the WAL sequence will
- *		tell whether to drop the file.
+ *		already because we are in a WAL replay sequence.
  */
 void
-smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isTemp, bool isRedo)
+smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
 {
-	XLogRecPtr	lsn;
-	XLogRecData rdata;
-	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.
@@ -374,69 +304,6 @@ smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isTemp, bool isRedo)
 							isRedo);
 
 	(*(smgrsw[reln->smgr_which].smgr_create)) (reln, forknum, isRedo);
-
-	if (isRedo)
-		return;
-
-	/*
-	 * Make an XLOG entry showing the file creation.  If we abort, the file
-	 * will be dropped at abort time.
-	 */
-	xlrec.rnode = reln->smgr_rnode;
-	xlrec.forknum = forknum;
-
-	rdata.data = (char *) &xlrec;
-	rdata.len = sizeof(xlrec);
-	rdata.buffer = InvalidBuffer;
-	rdata.next = NULL;
-
-	lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE, &rdata);
-
-	/* Add the relation to the list of stuff to delete at abort */
-	pending = (PendingRelDelete *)
-		MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
-	pending->relnode = reln->smgr_rnode;
-	pending->forknum = forknum;
-	pending->which = reln->smgr_which;
-	pending->isTemp = isTemp;
-	pending->atCommit = false;	/* delete if abort */
-	pending->nestLevel = GetCurrentTransactionNestLevel();
-	pending->next = pendingDeletes;
-	pendingDeletes = pending;
-}
-
-/*
- *	smgrscheduleunlink() -- Schedule unlinking a relation at xact commit.
- *
- *		The fork is marked to be removed from the store if we successfully
- *		commit the current transaction.
- */
-void
-smgrscheduleunlink(SMgrRelation reln, ForkNumber forknum, bool isTemp)
-{
-	PendingRelDelete *pending;
-
-	/* Add the relation to the list of stuff to delete at commit */
-	pending = (PendingRelDelete *)
-		MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
-	pending->relnode = reln->smgr_rnode;
-	pending->forknum = forknum;
-	pending->which = reln->smgr_which;
-	pending->isTemp = isTemp;
-	pending->atCommit = true;	/* delete if commit */
-	pending->nestLevel = GetCurrentTransactionNestLevel();
-	pending->next = pendingDeletes;
-	pendingDeletes = pending;
-
-	/*
-	 * NOTE: if the relation was created in this transaction, it will now be
-	 * present in the pending-delete list twice, once with atCommit true and
-	 * once with atCommit false.  Hence, it will be physically deleted at end
-	 * of xact in either case (and the other entry will be ignored by
-	 * smgrDoPendingDeletes, so no error will occur).  We could instead remove
-	 * the existing list entry and delete the physical file immediately, but
-	 * for now I'll keep the logic simple.
-	 */
 }
 
 /*
@@ -573,27 +440,6 @@ smgrtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks,
 	/* Do the truncation */
 	(*(smgrsw[reln->smgr_which].smgr_truncate)) (reln, forknum, nblocks,
 												 isTemp);
-
-	if (!isTemp)
-	{
-		/*
-		 * Make an XLOG entry showing the file truncation.
-		 */
-		XLogRecPtr	lsn;
-		XLogRecData rdata;
-		xl_smgr_truncate xlrec;
-
-		xlrec.blkno = nblocks;
-		xlrec.rnode = reln->smgr_rnode;
-		xlrec.forknum = forknum;
-
-		rdata.data = (char *) &xlrec;
-		rdata.len = sizeof(xlrec);
-		rdata.buffer = InvalidBuffer;
-		rdata.next = NULL;
-
-		lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE, &rdata);
-	}
 }
 
 /*
@@ -626,187 +472,6 @@ smgrimmedsync(SMgrRelation reln, ForkNumber forknum)
 }
 
 
-/*
- *	PostPrepare_smgr -- Clean up after a successful PREPARE
- *
- * What we have to do here is throw away the in-memory state about pending
- * relation deletes.  It's all been recorded in the 2PC state file and
- * it's no longer smgr's job to worry about it.
- */
-void
-PostPrepare_smgr(void)
-{
-	PendingRelDelete *pending;
-	PendingRelDelete *next;
-
-	for (pending = pendingDeletes; pending != NULL; pending = next)
-	{
-		next = pending->next;
-		pendingDeletes = next;
-		/* must explicitly free the list entry */
-		pfree(pending);
-	}
-}
-
-
-/*
- *	smgrDoPendingDeletes() -- Take care of relation deletes at end of xact.
- *
- * This also runs when aborting a subxact; we want to clean up a failed
- * subxact immediately.
- */
-void
-smgrDoPendingDeletes(bool isCommit)
-{
-	int			nestLevel = GetCurrentTransactionNestLevel();
-	PendingRelDelete *pending;
-	PendingRelDelete *prev;
-	PendingRelDelete *next;
-
-	prev = NULL;
-	for (pending = pendingDeletes; pending != NULL; pending = next)
-	{
-		next = pending->next;
-		if (pending->nestLevel < nestLevel)
-		{
-			/* outer-level entries should not be processed yet */
-			prev = pending;
-		}
-		else
-		{
-			/* unlink list entry first, so we don't retry on failure */
-			if (prev)
-				prev->next = next;
-			else
-				pendingDeletes = next;
-			/* do deletion if called for */
-			if (pending->atCommit == isCommit)
-				smgr_internal_unlink(pending->relnode,
-									 pending->forknum,
-									 pending->which,
-									 pending->isTemp,
-									 false);
-			/* must explicitly free the list entry */
-			pfree(pending);
-			/* prev does not change */
-		}
-	}
-}
-
-/*
- * smgrGetPendingDeletes() -- Get a list of relations to be deleted.
- *
- * The return value is the number of relations scheduled for termination.
- * *ptr is set to point to a freshly-palloc'd array of RelFileForks.
- * If there are no relations to be deleted, *ptr is set to NULL.
- *
- * If haveNonTemp isn't NULL, the bool it points to gets set to true if
- * there is any non-temp table pending to be deleted; false if not.
- *
- * Note that the list does not include anything scheduled for termination
- * by upper-level transactions.
- */
-int
-smgrGetPendingDeletes(bool forCommit, RelFileFork **ptr, bool *haveNonTemp)
-{
-	int			nestLevel = GetCurrentTransactionNestLevel();
-	int			nrels;
-	RelFileFork *rptr;
-	PendingRelDelete *pending;
-
-	nrels = 0;
-	if (haveNonTemp)
-		*haveNonTemp = false;
-	for (pending = pendingDeletes; pending != NULL; pending = pending->next)
-	{
-		if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
-			nrels++;
-	}
-	if (nrels == 0)
-	{
-		*ptr = NULL;
-		return 0;
-	}
-	rptr = (RelFileFork *) palloc(nrels * sizeof(RelFileFork));
-	*ptr = rptr;
-	for (pending = pendingDeletes; pending != NULL; pending = pending->next)
-	{
-		if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
-		{
-			rptr->rnode = pending->relnode;
-			rptr->forknum = pending->forknum;
-			rptr++;
-		}
-		if (haveNonTemp && !pending->isTemp)
-			*haveNonTemp = true;
-	}
-	return nrels;
-}
-
-/*
- * AtSubCommit_smgr() --- Take care of subtransaction commit.
- *
- * Reassign all items in the pending-deletes list to the parent transaction.
- */
-void
-AtSubCommit_smgr(void)
-{
-	int			nestLevel = GetCurrentTransactionNestLevel();
-	PendingRelDelete *pending;
-
-	for (pending = pendingDeletes; pending != NULL; pending = pending->next)
-	{
-		if (pending->nestLevel >= nestLevel)
-			pending->nestLevel = nestLevel - 1;
-	}
-}
-
-/*
- * AtSubAbort_smgr() --- Take care of subtransaction abort.
- *
- * Delete created relations and forget about deleted relations.
- * We can execute these operations immediately because we know this
- * subtransaction will not commit.
- */
-void
-AtSubAbort_smgr(void)
-{
-	smgrDoPendingDeletes(false);
-}
-
-/*
- *	smgrcommit() -- Prepare to commit changes made during the current
- *					transaction.
- *
- *		This is called before we actually commit.
- */
-void
-smgrcommit(void)
-{
-	int			i;
-
-	for (i = 0; i < NSmgr; i++)
-	{
-		if (smgrsw[i].smgr_commit)
-			(*(smgrsw[i].smgr_commit)) ();
-	}
-}
-
-/*
- *	smgrabort() -- Clean up after transaction abort.
- */
-void
-smgrabort(void)
-{
-	int			i;
-
-	for (i = 0; i < NSmgr; i++)
-	{
-		if (smgrsw[i].smgr_abort)
-			(*(smgrsw[i].smgr_abort)) ();
-	}
-}
-
 /*
  *	smgrpreckpt() -- Prepare for checkpoint.
  */
@@ -852,80 +517,3 @@ smgrpostckpt(void)
 	}
 }
 
-
-void
-smgr_redo(XLogRecPtr lsn, XLogRecord *record)
-{
-	uint8		info = record->xl_info & ~XLR_INFO_MASK;
-
-	if (info == XLOG_SMGR_CREATE)
-	{
-		xl_smgr_create *xlrec = (xl_smgr_create *) XLogRecGetData(record);
-		SMgrRelation reln;
-
-		reln = smgropen(xlrec->rnode);
-		smgrcreate(reln, xlrec->forknum, false, true);
-	}
-	else if (info == XLOG_SMGR_TRUNCATE)
-	{
-		xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
-		SMgrRelation reln;
-
-		reln = smgropen(xlrec->rnode);
-
-		/*
-		 * Forcibly create relation if it doesn't exist (which suggests that
-		 * it was dropped somewhere later in the WAL sequence).  As in
-		 * XLogOpenRelation, we prefer to recreate the rel and replay the log
-		 * as best we can until the drop is seen.
-		 */
-		smgrcreate(reln, xlrec->forknum, false, true);
-
-		/* Can't use smgrtruncate because it would try to xlog */
-
-		/*
-		 * First, force bufmgr to drop any buffers it has for the to-be-
-		 * truncated blocks.  We must do this, else subsequent XLogReadBuffer
-		 * operations will not re-extend the file properly.
-		 */
-		DropRelFileNodeBuffers(xlrec->rnode, xlrec->forknum, false,
-							   xlrec->blkno);
-
-		/* Do the truncation */
-		(*(smgrsw[reln->smgr_which].smgr_truncate)) (reln,
-													 xlrec->forknum,
-													 xlrec->blkno,
-													 false);
-
-		/* Also tell xlogutils.c about it */
-		XLogTruncateRelation(xlrec->rnode, xlrec->forknum, xlrec->blkno);
-	}
-	else
-		elog(PANIC, "smgr_redo: unknown op code %u", info);
-}
-
-void
-smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
-{
-	uint8		info = xl_info & ~XLR_INFO_MASK;
-
-	if (info == XLOG_SMGR_CREATE)
-	{
-		xl_smgr_create *xlrec = (xl_smgr_create *) rec;
-		char *path = relpath(xlrec->rnode, xlrec->forknum);
-
-		appendStringInfo(buf, "file create: %s", path);
-		pfree(path);
-	}
-	else if (info == XLOG_SMGR_TRUNCATE)
-	{
-		xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
-		char *path = relpath(xlrec->rnode, xlrec->forknum);
-
-		appendStringInfo(buf, "file truncate: %s to %u blocks", path,
-						 xlrec->blkno);
-		pfree(path);
-	}
-	else
-		appendStringInfo(buf, "UNKNOWN");
-}
diff --git a/src/include/access/rmgr.h b/src/include/access/rmgr.h
index 6f018f0bee2..44b8a07a3fc 100644
--- a/src/include/access/rmgr.h
+++ b/src/include/access/rmgr.h
@@ -3,7 +3,7 @@
  *
  * Resource managers definition
  *
- * $PostgreSQL: pgsql/src/include/access/rmgr.h,v 1.18 2008/09/30 10:52:13 heikki Exp $
+ * $PostgreSQL: pgsql/src/include/access/rmgr.h,v 1.19 2008/11/19 10:34:52 heikki Exp $
  */
 #ifndef RMGR_H
 #define RMGR_H
@@ -23,7 +23,6 @@ typedef uint8 RmgrId;
 #define RM_DBASE_ID				4
 #define RM_TBLSPC_ID			5
 #define RM_MULTIXACT_ID			6
-#define RM_FREESPACE_ID			7
 #define RM_HEAP2_ID				9
 #define RM_HEAP_ID				10
 #define RM_BTREE_ID				11
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index c887716e591..b6439bd2945 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.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/xact.h,v 1.95 2008/08/11 11:05:11 heikki Exp $
+ * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.96 2008/11/19 10:34:52 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,10 +88,10 @@ typedef void (*SubXactCallback) (SubXactEvent event, SubTransactionId mySubid,
 typedef struct xl_xact_commit
 {
 	TimestampTz xact_time;		/* time of commit */
-	int			nrels;			/* number of RelFileForks */
+	int			nrels;			/* number of RelFileNodes */
 	int			nsubxacts;		/* number of subtransaction XIDs */
-	/* Array of RelFileFork(s) to drop at commit */
-	RelFileFork	xnodes[1];		/* VARIABLE LENGTH ARRAY */
+	/* Array of RelFileNode(s) to drop at commit */
+	RelFileNode	xnodes[1];		/* VARIABLE LENGTH ARRAY */
 	/* ARRAY OF COMMITTED SUBTRANSACTION XIDs FOLLOWS */
 } xl_xact_commit;
 
@@ -100,10 +100,10 @@ typedef struct xl_xact_commit
 typedef struct xl_xact_abort
 {
 	TimestampTz xact_time;		/* time of abort */
-	int			nrels;			/* number of RelFileForks */
+	int			nrels;			/* number of RelFileNodes */
 	int			nsubxacts;		/* number of subtransaction XIDs */
-	/* Array of RelFileFork(s) to drop at abort */
-	RelFileFork	xnodes[1];		/* VARIABLE LENGTH ARRAY */
+	/* Array of RelFileNode(s) to drop at abort */
+	RelFileNode	xnodes[1];		/* VARIABLE LENGTH ARRAY */
 	/* ARRAY OF ABORTED SUBTRANSACTION XIDs FOLLOWS */
 } xl_xact_abort;
 
diff --git a/src/include/catalog/storage.h b/src/include/catalog/storage.h
new file mode 100644
index 00000000000..c5caa1283f2
--- /dev/null
+++ b/src/include/catalog/storage.h
@@ -0,0 +1,39 @@
+/*-------------------------------------------------------------------------
+ *
+ * storage.h
+ *	  prototypes for functions in backend/catalog/storage.c
+ *
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/catalog/storage.h,v 1.1 2008/11/19 10:34:52 heikki Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef STORAGE_H
+#define STORAGE_H
+
+#include "storage/block.h"
+#include "storage/relfilenode.h"
+#include "utils/rel.h"
+
+extern void RelationCreateStorage(RelFileNode rnode, bool istemp);
+extern void RelationDropStorage(Relation rel);
+extern void RelationTruncate(Relation rel, BlockNumber nblocks);
+
+/*
+ * These functions used to be in storage/smgr/smgr.c, which explains the
+ * naming
+ */
+extern void smgrDoPendingDeletes(bool isCommit);
+extern int smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr,
+					  bool *haveNonTemp);
+extern void AtSubCommit_smgr(void);
+extern void AtSubAbort_smgr(void);
+extern void PostPrepare_smgr(void);
+
+extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
+extern void smgr_desc(StringInfo buf, uint8 xl_info, char *rec);
+
+#endif   /* STORAGE_H */
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index f2252c8f460..4e8ae41ab70 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.117 2008/11/06 20:51:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.118 2008/11/19 10:34:52 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -176,7 +176,6 @@ extern void PrintBufferLeakWarning(Buffer buffer);
 extern void CheckPointBuffers(int flags);
 extern BlockNumber BufferGetBlockNumber(Buffer buffer);
 extern BlockNumber RelationGetNumberOfBlocks(Relation relation);
-extern void RelationTruncate(Relation rel, BlockNumber nblocks);
 extern void FlushRelationBuffers(Relation rel);
 extern void FlushDatabaseBuffers(Oid dbid);
 extern void DropRelFileNodeBuffers(RelFileNode rnode, ForkNumber forkNum,
diff --git a/src/include/storage/freespace.h b/src/include/storage/freespace.h
index 858be595284..e9490933dbe 100644
--- a/src/include/storage/freespace.h
+++ b/src/include/storage/freespace.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/freespace.h,v 1.30 2008/10/31 19:40:27 heikki Exp $
+ * $PostgreSQL: pgsql/src/include/storage/freespace.h,v 1.31 2008/11/19 10:34:52 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,8 +33,4 @@ extern void XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk,
 extern void FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks);
 extern void FreeSpaceMapVacuum(Relation rel);
 
-/* WAL prototypes */
-extern void fsm_desc(StringInfo buf, uint8 xl_info, char *rec);
-extern void fsm_redo(XLogRecPtr lsn, XLogRecord *record);
-
 #endif   /* FREESPACE_H */
diff --git a/src/include/storage/indexfsm.h b/src/include/storage/indexfsm.h
index 36872076f87..d09732f5abe 100644
--- a/src/include/storage/indexfsm.h
+++ b/src/include/storage/indexfsm.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/indexfsm.h,v 1.2 2008/10/06 08:04:11 heikki Exp $
+ * $PostgreSQL: pgsql/src/include/storage/indexfsm.h,v 1.3 2008/11/19 10:34:52 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,8 +20,6 @@ extern BlockNumber GetFreeIndexPage(Relation rel);
 extern void RecordFreeIndexPage(Relation rel, BlockNumber page);
 extern void RecordUsedIndexPage(Relation rel, BlockNumber page);
 
-extern void InitIndexFreeSpaceMap(Relation rel);
-extern void IndexFreeSpaceMapTruncate(Relation rel, BlockNumber nblocks);
 extern void IndexFreeSpaceMapVacuum(Relation rel);
 
 #endif   /* INDEXFSM_H */
diff --git a/src/include/storage/relfilenode.h b/src/include/storage/relfilenode.h
index 383cc18a578..adedad61b33 100644
--- a/src/include/storage/relfilenode.h
+++ b/src/include/storage/relfilenode.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/relfilenode.h,v 1.19 2008/10/06 14:13:17 heikki Exp $
+ * $PostgreSQL: pgsql/src/include/storage/relfilenode.h,v 1.20 2008/11/19 10:34:52 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -78,13 +78,4 @@ typedef struct RelFileNode
 	 (node1).dbNode == (node2).dbNode && \
 	 (node1).spcNode == (node2).spcNode)
 
-/*
- * RelFileFork identifies a particular fork of a relation.
- */
-typedef struct RelFileFork
-{
-	RelFileNode rnode;
-	ForkNumber forknum;
-} RelFileFork;
-
 #endif   /* RELFILENODE_H */
diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h
index d4999c1049a..edc230f0b68 100644
--- a/src/include/storage/smgr.h
+++ b/src/include/storage/smgr.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/smgr.h,v 1.63 2008/08/11 11:05:11 heikki Exp $
+ * $PostgreSQL: pgsql/src/include/storage/smgr.h,v 1.64 2008/11/19 10:34:52 heikki Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -65,10 +65,7 @@ extern void smgrsetowner(SMgrRelation *owner, SMgrRelation reln);
 extern void smgrclose(SMgrRelation reln);
 extern void smgrcloseall(void);
 extern void smgrclosenode(RelFileNode rnode);
-extern void smgrcreate(SMgrRelation reln, ForkNumber forknum,
-					   bool isTemp, bool isRedo);
-extern void smgrscheduleunlink(SMgrRelation reln, ForkNumber forknum,
-							   bool isTemp);
+extern void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo);
 extern void smgrdounlink(SMgrRelation reln, ForkNumber forknum,
 						 bool isTemp, bool isRedo);
 extern void smgrextend(SMgrRelation reln, ForkNumber forknum, 
@@ -81,21 +78,10 @@ extern BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum);
 extern void smgrtruncate(SMgrRelation reln, ForkNumber forknum,
 						 BlockNumber nblocks, bool isTemp);
 extern void smgrimmedsync(SMgrRelation reln, ForkNumber forknum);
-extern void smgrDoPendingDeletes(bool isCommit);
-extern int smgrGetPendingDeletes(bool forCommit, RelFileFork **ptr,
-					  bool *haveNonTemp);
-extern void AtSubCommit_smgr(void);
-extern void AtSubAbort_smgr(void);
-extern void PostPrepare_smgr(void);
-extern void smgrcommit(void);
-extern void smgrabort(void);
 extern void smgrpreckpt(void);
 extern void smgrsync(void);
 extern void smgrpostckpt(void);
 
-extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
-extern void smgr_desc(StringInfo buf, uint8 xl_info, char *rec);
-
 
 /* internals: move me elsewhere -- ay 7/94 */
 
-- 
GitLab