summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeikki Linnakangas2008-11-19 10:34:52 +0000
committerHeikki Linnakangas2008-11-19 10:34:52 +0000
commit4c2329e4eaa5cb131c09a0e396cab9f9922231fc (patch)
tree54e873f61c42a87f3409dcdaec14e954b1d99cd3
parenta9f3139f7b5e3805f5173f58849d344596d84de4 (diff)
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.
-rw-r--r--src/backend/access/gin/gininsert.c3
-rw-r--r--src/backend/access/gin/ginvacuum.c2
-rw-r--r--src/backend/access/gist/gist.c3
-rw-r--r--src/backend/access/gist/gistvacuum.c2
-rw-r--r--src/backend/access/heap/heapam.c4
-rw-r--r--src/backend/access/nbtree/nbtree.c5
-rw-r--r--src/backend/access/transam/rmgr.c4
-rw-r--r--src/backend/access/transam/twophase.c71
-rw-r--r--src/backend/access/transam/xact.c46
-rw-r--r--src/backend/access/transam/xlogutils.c2
-rw-r--r--src/backend/catalog/Makefile2
-rw-r--r--src/backend/catalog/heap.c25
-rw-r--r--src/backend/catalog/index.c40
-rw-r--r--src/backend/catalog/storage.c462
-rw-r--r--src/backend/commands/tablecmds.c19
-rw-r--r--src/backend/commands/vacuum.c3
-rw-r--r--src/backend/commands/vacuumlazy.c2
-rw-r--r--src/backend/rewrite/rewriteDefine.c13
-rw-r--r--src/backend/storage/buffer/bufmgr.c22
-rw-r--r--src/backend/storage/freespace/freespace.c155
-rw-r--r--src/backend/storage/freespace/indexfsm.c26
-rw-r--r--src/backend/storage/smgr/smgr.c418
-rw-r--r--src/include/access/rmgr.h1
-rw-r--r--src/include/access/xact.h12
-rw-r--r--src/include/catalog/storage.h39
-rw-r--r--src/include/storage/bufmgr.h1
-rw-r--r--src/include/storage/freespace.h4
-rw-r--r--src/include/storage/indexfsm.h2
-rw-r--r--src/include/storage/relfilenode.h9
-rw-r--r--src/include/storage/smgr.h16
30 files changed, 647 insertions, 766 deletions
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index dd805c9f8f..4be89bc925 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -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 7db7d7c2a8..b180cd7bfb 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -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 58050803be..7b3b6c7a7b 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -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 82be008e6b..51bbe7e0a0 100644
--- a/src/backend/access/gist/gistvacuum.c
+++ b/src/backend/access/gist/gistvacuum.c
@@ -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 33d5fabf14..c0ec48c594 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -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 825ff5c6a2..86b0eddf42 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -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 785d920caa..0273b0e153 100644
--- a/src/backend/access/transam/rmgr.c
+++ b/src/backend/access/transam/rmgr.c
@@ -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 55896380c1..8a6b8bdfd1 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -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 b7d1285402..f32df1a888 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -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 d06e090b1d..3f7ea192d8 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -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 39714f0cb3..6a27133c9e 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -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 afc6977095..fbf1287059 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -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 e244f92f0b..0e8268a15a 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -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 0000000000..db656383dc
--- /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$
+ *
+ * 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 655947051b..423808d93d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -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 db645ccca8..8883bb4ae6 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -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 f71d02b1f9..b562127e56 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -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 10cd5abccf..ac7a29aa3a 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -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 74a99bd3f2..adb6c5d4c3 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -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 4949cf6d8e..622b4b1822 100644
--- a/src/backend/storage/freespace/freespace.c
+++ b/src/backend/storage/freespace/freespace.c
@@ -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);
@@ -307,42 +303,11 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks)
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 7e33879682..f3558bd10f 100644
--- a/src/backend/storage/freespace/indexfsm.c
+++ b/src/backend/storage/freespace/indexfsm.c
@@ -31,20 +31,6 @@
*/
/*
- * 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
*
* As a side effect, the page is marked as used in the FSM.
@@ -80,18 +66,6 @@ RecordUsedIndexPage(Relation rel, BlockNumber usedBlock)
}
/*
- * 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
*/
void
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index 43302dc09a..ddbf2c3120 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -17,7 +17,6 @@
*/
#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);
- }
}
/*
@@ -627,187 +473,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.
*/
void
@@ -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 173b01639b..5702f5f4d0 100644
--- a/src/include/access/rmgr.h
+++ b/src/include/access/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 dad6ef8d20..ec1a3ef0d5 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -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 0000000000..8fc5f209e9
--- /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$
+ *
+ *-------------------------------------------------------------------------
+ */
+#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 0fd875231c..4e0d7b2ea2 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -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 e17a8d5d2d..b76acd8f60 100644
--- a/src/include/storage/freespace.h
+++ b/src/include/storage/freespace.h
@@ -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 53e7b2025f..c5c6170f31 100644
--- a/src/include/storage/indexfsm.h
+++ b/src/include/storage/indexfsm.h
@@ -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 cb0d44ef31..b941d5535a 100644
--- a/src/include/storage/relfilenode.h
+++ b/src/include/storage/relfilenode.h
@@ -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 3e20ea1955..9e7971ada6 100644
--- a/src/include/storage/smgr.h
+++ b/src/include/storage/smgr.h
@@ -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 */