diff options
author | Heikki Linnakangas | 2008-11-19 10:34:52 +0000 |
---|---|---|
committer | Heikki Linnakangas | 2008-11-19 10:34:52 +0000 |
commit | 3396000684b41e7e9467d1abc67152b39e697035 (patch) | |
tree | c8edf238f89cd7b0b1562b919f2addebc67eb54e | |
parent | 26e6c896c946bc1a9e9f608b2c7463be1e8c6291 (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.
30 files changed, 675 insertions, 794 deletions
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); @@ -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 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: @@ -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 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); - } } /* @@ -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 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 */ |