From 3396000684b41e7e9467d1abc67152b39e697035 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas 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 6e0a194a69..54bfa92853 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 c49926c3fd..4cc9aaf47d 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 1dff6d2f2a..1b5946e889 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 d933fea25b..e6f3502f82 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 7139b03471..f6d75c6e2b 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 bd486afabb..32a92d8cc2 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 7c62ec3854..44c3cd7769 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 1148009844..369fe97588 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 3d51e35768..b61fe41083 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 baf0878bed..b481a5ef1d 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 9023c795ec..bb4c42135c 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 bb5b263ee6..769b3b6357 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 a278d90c2b..108241be99 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 0000000000..c8187d511c --- /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 2af083fd13..d252632ee7 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 aa4c18915a..9cb641fe3f 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 246962a414..4230b2e3ef 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 6212add6bc..2df21b5e35 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 bb4b968f1c..b7e0861e2b 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 10cca029d1..013b4ce221 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 768b633f08..58d8e6caf2 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 820d491040..f6dd2b8221 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 6f018f0bee..44b8a07a3f 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 c887716e59..b6439bd294 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 0000000000..c5caa1283f --- /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 f2252c8f46..4e8ae41ab7 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 858be59528..e9490933db 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 36872076f8..d09732f5ab 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 383cc18a57..adedad61b3 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 d4999c1049..edc230f0b6 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 */ -- 2.40.0