aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/hash/hashpage.c8
-rw-r--r--src/backend/access/heap/heapam.c10
-rw-r--r--src/backend/access/heap/rewriteheap.c10
-rw-r--r--src/backend/access/nbtree/nbtsort.c15
-rw-r--r--src/backend/access/transam/twophase.c54
-rw-r--r--src/backend/access/transam/xact.c44
-rw-r--r--src/backend/access/transam/xlog.c8
-rw-r--r--src/backend/access/transam/xlogutils.c59
-rw-r--r--src/backend/catalog/catalog.c39
-rw-r--r--src/backend/catalog/heap.c18
-rw-r--r--src/backend/catalog/index.c40
-rw-r--r--src/backend/commands/tablecmds.c72
-rw-r--r--src/backend/postmaster/bgwriter.c7
-rw-r--r--src/backend/rewrite/rewriteDefine.c10
-rw-r--r--src/backend/storage/buffer/bufmgr.c104
-rw-r--r--src/backend/storage/buffer/localbuf.c12
-rw-r--r--src/backend/storage/smgr/README19
-rw-r--r--src/backend/storage/smgr/md.c299
-rw-r--r--src/backend/storage/smgr/smgr.c176
-rw-r--r--src/backend/utils/adt/dbsize.c5
-rw-r--r--src/include/access/heapam.h5
-rw-r--r--src/include/access/htup.h3
-rw-r--r--src/include/access/xact.h14
-rw-r--r--src/include/access/xlog_internal.h3
-rw-r--r--src/include/access/xlogutils.h9
-rw-r--r--src/include/catalog/catalog.h4
-rw-r--r--src/include/postmaster/bgwriter.h5
-rw-r--r--src/include/storage/buf_internals.h16
-rw-r--r--src/include/storage/bufmgr.h15
-rw-r--r--src/include/storage/relfilenode.h30
-rw-r--r--src/include/storage/smgr.h66
31 files changed, 733 insertions, 446 deletions
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index 4c013146d4e..43ec69cab32 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.75 2008/05/12 00:00:44 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.76 2008/08/11 11:05:10 heikki Exp $
*
* NOTES
* Postgres hash pages look like ordinary relation pages. The opaque
@@ -158,7 +158,7 @@ _hash_getinitbuf(Relation rel, BlockNumber blkno)
if (blkno == P_NEW)
elog(ERROR, "hash AM does not use P_NEW");
- buf = ReadOrZeroBuffer(rel, blkno);
+ buf = ReadOrZeroBuffer(rel, MAIN_FORKNUM, blkno);
LockBuffer(buf, HASH_WRITE);
@@ -203,7 +203,7 @@ _hash_getnewbuf(Relation rel, BlockNumber blkno)
BufferGetBlockNumber(buf), blkno);
}
else
- buf = ReadOrZeroBuffer(rel, blkno);
+ buf = ReadOrZeroBuffer(rel, MAIN_FORKNUM, blkno);
LockBuffer(buf, HASH_WRITE);
@@ -737,7 +737,7 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
MemSet(zerobuf, 0, sizeof(zerobuf));
RelationOpenSmgr(rel);
- smgrextend(rel->rd_smgr, lastblock, zerobuf, rel->rd_istemp);
+ smgrextend(rel->rd_smgr, MAIN_FORKNUM, lastblock, zerobuf, rel->rd_istemp);
return true;
}
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index cb2f428afe6..6d3528323bf 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.261 2008/07/13 20:45:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.262 2008/08/11 11:05:10 heikki Exp $
*
*
* INTERFACE ROUTINES
@@ -3906,7 +3906,8 @@ log_heap_move(Relation reln, Buffer oldbuf, ItemPointerData from,
* not do anything that assumes we are touching a heap.
*/
XLogRecPtr
-log_newpage(RelFileNode *rnode, BlockNumber blkno, Page page)
+log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno,
+ Page page)
{
xl_heap_newpage xlrec;
XLogRecPtr recptr;
@@ -3916,6 +3917,7 @@ log_newpage(RelFileNode *rnode, BlockNumber blkno, Page page)
START_CRIT_SECTION();
xlrec.node = *rnode;
+ xlrec.forknum = forkNum;
xlrec.blkno = blkno;
rdata[0].data = (char *) &xlrec;
@@ -4714,7 +4716,7 @@ heap_sync(Relation rel)
/* main heap */
FlushRelationBuffers(rel);
/* FlushRelationBuffers will have opened rd_smgr */
- smgrimmedsync(rel->rd_smgr);
+ smgrimmedsync(rel->rd_smgr, MAIN_FORKNUM);
/* toast heap, if any */
if (OidIsValid(rel->rd_rel->reltoastrelid))
@@ -4723,7 +4725,7 @@ heap_sync(Relation rel)
toastrel = heap_open(rel->rd_rel->reltoastrelid, AccessShareLock);
FlushRelationBuffers(toastrel);
- smgrimmedsync(toastrel->rd_smgr);
+ smgrimmedsync(toastrel->rd_smgr, MAIN_FORKNUM);
heap_close(toastrel, AccessShareLock);
}
}
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 57a7430244a..cd7302bd5d7 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -96,7 +96,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/rewriteheap.c,v 1.14 2008/06/19 00:46:03 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/rewriteheap.c,v 1.15 2008/08/11 11:05:10 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -270,10 +270,11 @@ end_heap_rewrite(RewriteState state)
{
if (state->rs_use_wal)
log_newpage(&state->rs_new_rel->rd_node,
+ MAIN_FORKNUM,
state->rs_blockno,
state->rs_buffer);
RelationOpenSmgr(state->rs_new_rel);
- smgrextend(state->rs_new_rel->rd_smgr, state->rs_blockno,
+ smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM, state->rs_blockno,
(char *) state->rs_buffer, true);
}
@@ -606,6 +607,7 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
/* XLOG stuff */
if (state->rs_use_wal)
log_newpage(&state->rs_new_rel->rd_node,
+ MAIN_FORKNUM,
state->rs_blockno,
page);
@@ -616,8 +618,8 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
* end_heap_rewrite.
*/
RelationOpenSmgr(state->rs_new_rel);
- smgrextend(state->rs_new_rel->rd_smgr, state->rs_blockno,
- (char *) page, true);
+ smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM,
+ state->rs_blockno, (char *) page, true);
state->rs_blockno++;
state->rs_buffer_valid = false;
diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index 5fdccd2fb14..7dcfa10eeec 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -57,7 +57,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.116 2008/06/19 00:46:03 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.117 2008/08/11 11:05:10 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -267,7 +267,7 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
if (wstate->btws_use_wal)
{
/* We use the heap NEWPAGE record type for this */
- log_newpage(&wstate->index->rd_node, blkno, page);
+ log_newpage(&wstate->index->rd_node, MAIN_FORKNUM, blkno, page);
}
else
{
@@ -286,7 +286,8 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
{
if (!wstate->btws_zeropage)
wstate->btws_zeropage = (Page) palloc0(BLCKSZ);
- smgrextend(wstate->index->rd_smgr, wstate->btws_pages_written++,
+ smgrextend(wstate->index->rd_smgr, MAIN_FORKNUM,
+ wstate->btws_pages_written++,
(char *) wstate->btws_zeropage,
true);
}
@@ -299,13 +300,15 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
if (blkno == wstate->btws_pages_written)
{
/* extending the file... */
- smgrextend(wstate->index->rd_smgr, blkno, (char *) page, true);
+ smgrextend(wstate->index->rd_smgr, MAIN_FORKNUM, blkno,
+ (char *) page, true);
wstate->btws_pages_written++;
}
else
{
/* overwriting a block we zero-filled before */
- smgrwrite(wstate->index->rd_smgr, blkno, (char *) page, true);
+ smgrwrite(wstate->index->rd_smgr, MAIN_FORKNUM, blkno,
+ (char *) page, true);
}
pfree(page);
@@ -809,6 +812,6 @@ _bt_load(BTWriteState *wstate, BTSpool *btspool, BTSpool *btspool2)
if (!wstate->index->rd_istemp)
{
RelationOpenSmgr(wstate->index);
- smgrimmedsync(wstate->index->rd_smgr);
+ smgrimmedsync(wstate->index->rd_smgr, MAIN_FORKNUM);
}
}
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 57eb7eeea49..b86bdc36677 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.44 2008/08/01 13:16:08 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.45 2008/08/11 11:05:10 heikki Exp $
*
* NOTES
* Each global transaction is associated with a global transaction
@@ -141,12 +141,12 @@ static void RecordTransactionCommitPrepared(TransactionId xid,
int nchildren,
TransactionId *children,
int nrels,
- RelFileNode *rels);
+ RelFileFork *rels);
static void RecordTransactionAbortPrepared(TransactionId xid,
int nchildren,
TransactionId *children,
int nrels,
- RelFileNode *rels);
+ RelFileFork *rels);
static void ProcessRecords(char *bufptr, TransactionId xid,
const TwoPhaseCallback callbacks[]);
@@ -694,8 +694,8 @@ TwoPhaseGetDummyProc(TransactionId xid)
*
* 1. TwoPhaseFileHeader
* 2. TransactionId[] (subtransactions)
- * 3. RelFileNode[] (files to be deleted at commit)
- * 4. RelFileNode[] (files to be deleted at abort)
+ * 3. RelFileFork[] (files to be deleted at commit)
+ * 4. RelFileFork[] (files to be deleted at abort)
* 5. TwoPhaseRecordOnDisk
* 6. ...
* 7. TwoPhaseRecordOnDisk (end sentinel, rmid == TWOPHASE_RM_END_ID)
@@ -793,8 +793,8 @@ StartPrepare(GlobalTransaction gxact)
TransactionId xid = gxact->proc.xid;
TwoPhaseFileHeader hdr;
TransactionId *children;
- RelFileNode *commitrels;
- RelFileNode *abortrels;
+ RelFileFork *commitrels;
+ RelFileFork *abortrels;
/* Initialize linked list */
records.head = palloc0(sizeof(XLogRecData));
@@ -832,12 +832,12 @@ StartPrepare(GlobalTransaction gxact)
}
if (hdr.ncommitrels > 0)
{
- save_state_data(commitrels, hdr.ncommitrels * sizeof(RelFileNode));
+ save_state_data(commitrels, hdr.ncommitrels * sizeof(RelFileFork));
pfree(commitrels);
}
if (hdr.nabortrels > 0)
{
- save_state_data(abortrels, hdr.nabortrels * sizeof(RelFileNode));
+ save_state_data(abortrels, hdr.nabortrels * sizeof(RelFileFork));
pfree(abortrels);
}
}
@@ -1140,8 +1140,8 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
TwoPhaseFileHeader *hdr;
TransactionId latestXid;
TransactionId *children;
- RelFileNode *commitrels;
- RelFileNode *abortrels;
+ RelFileFork *commitrels;
+ RelFileFork *abortrels;
int i;
/*
@@ -1169,10 +1169,10 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
bufptr = buf + MAXALIGN(sizeof(TwoPhaseFileHeader));
children = (TransactionId *) bufptr;
bufptr += MAXALIGN(hdr->nsubxacts * sizeof(TransactionId));
- commitrels = (RelFileNode *) bufptr;
- bufptr += MAXALIGN(hdr->ncommitrels * sizeof(RelFileNode));
- abortrels = (RelFileNode *) bufptr;
- bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileNode));
+ commitrels = (RelFileFork *) bufptr;
+ bufptr += MAXALIGN(hdr->ncommitrels * sizeof(RelFileFork));
+ abortrels = (RelFileFork *) bufptr;
+ bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileFork));
/* compute latestXid among all children */
latestXid = TransactionIdLatest(xid, hdr->nsubxacts, children);
@@ -1215,12 +1215,20 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
if (isCommit)
{
for (i = 0; i < hdr->ncommitrels; i++)
- smgrdounlink(smgropen(commitrels[i]), false, false);
+ {
+ SMgrRelation srel = smgropen(commitrels[i].rnode);
+ smgrdounlink(srel, commitrels[i].forknum, false, false);
+ smgrclose(srel);
+ }
}
else
{
for (i = 0; i < hdr->nabortrels; i++)
- smgrdounlink(smgropen(abortrels[i]), false, false);
+ {
+ SMgrRelation srel = smgropen(abortrels[i].rnode);
+ smgrdounlink(srel, abortrels[i].forknum, false, false);
+ smgrclose(srel);
+ }
}
/* And now do the callbacks */
@@ -1631,8 +1639,8 @@ RecoverPreparedTransactions(void)
bufptr = buf + MAXALIGN(sizeof(TwoPhaseFileHeader));
subxids = (TransactionId *) bufptr;
bufptr += MAXALIGN(hdr->nsubxacts * sizeof(TransactionId));
- bufptr += MAXALIGN(hdr->ncommitrels * sizeof(RelFileNode));
- bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileNode));
+ bufptr += MAXALIGN(hdr->ncommitrels * sizeof(RelFileFork));
+ bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileFork));
/*
* Reconstruct subtrans state for the transaction --- needed
@@ -1685,7 +1693,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
int nchildren,
TransactionId *children,
int nrels,
- RelFileNode *rels)
+ RelFileFork *rels)
{
XLogRecData rdata[3];
int lastrdata = 0;
@@ -1710,7 +1718,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
{
rdata[0].next = &(rdata[1]);
rdata[1].data = (char *) rels;
- rdata[1].len = nrels * sizeof(RelFileNode);
+ rdata[1].len = nrels * sizeof(RelFileFork);
rdata[1].buffer = InvalidBuffer;
lastrdata = 1;
}
@@ -1760,7 +1768,7 @@ RecordTransactionAbortPrepared(TransactionId xid,
int nchildren,
TransactionId *children,
int nrels,
- RelFileNode *rels)
+ RelFileFork *rels)
{
XLogRecData rdata[3];
int lastrdata = 0;
@@ -1790,7 +1798,7 @@ RecordTransactionAbortPrepared(TransactionId xid,
{
rdata[0].next = &(rdata[1]);
rdata[1].data = (char *) rels;
- rdata[1].len = nrels * sizeof(RelFileNode);
+ rdata[1].len = nrels * sizeof(RelFileFork);
rdata[1].buffer = InvalidBuffer;
lastrdata = 1;
}
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 10645b2b7fb..5f6c9df677a 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.264 2008/05/12 20:01:58 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.265 2008/08/11 11:05:10 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -819,7 +819,7 @@ RecordTransactionCommit(void)
bool markXidCommitted = TransactionIdIsValid(xid);
TransactionId latestXid = InvalidTransactionId;
int nrels;
- RelFileNode *rels;
+ RelFileFork *rels;
bool haveNonTemp;
int nchildren;
TransactionId *children;
@@ -900,7 +900,7 @@ RecordTransactionCommit(void)
{
rdata[0].next = &(rdata[1]);
rdata[1].data = (char *) rels;
- rdata[1].len = nrels * sizeof(RelFileNode);
+ rdata[1].len = nrels * sizeof(RelFileFork);
rdata[1].buffer = InvalidBuffer;
lastrdata = 1;
}
@@ -1203,7 +1203,7 @@ RecordTransactionAbort(bool isSubXact)
TransactionId xid = GetCurrentTransactionIdIfAny();
TransactionId latestXid;
int nrels;
- RelFileNode *rels;
+ RelFileFork *rels;
int nchildren;
TransactionId *children;
XLogRecData rdata[3];
@@ -1264,7 +1264,7 @@ RecordTransactionAbort(bool isSubXact)
{
rdata[0].next = &(rdata[1]);
rdata[1].data = (char *) rels;
- rdata[1].len = nrels * sizeof(RelFileNode);
+ rdata[1].len = nrels * sizeof(RelFileFork);
rdata[1].buffer = InvalidBuffer;
lastrdata = 1;
}
@@ -4282,8 +4282,13 @@ 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++)
{
- XLogDropRelation(xlrec->xnodes[i]);
- smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
+ SMgrRelation srel;
+
+ XLogDropRelation(xlrec->xnodes[i].rnode, xlrec->xnodes[i].forknum);
+
+ srel = smgropen(xlrec->xnodes[i].rnode);
+ smgrdounlink(srel, xlrec->xnodes[i].forknum, false, true);
+ smgrclose(srel);
}
}
@@ -4317,8 +4322,13 @@ 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++)
{
- XLogDropRelation(xlrec->xnodes[i]);
- smgrdounlink(smgropen(xlrec->xnodes[i]), false, true);
+ SMgrRelation srel;
+
+ XLogDropRelation(xlrec->xnodes[i].rnode, xlrec->xnodes[i].forknum);
+
+ srel = smgropen(xlrec->xnodes[i].rnode);
+ smgrdounlink(srel, xlrec->xnodes[i].forknum, false, true);
+ smgrclose(srel);
}
}
@@ -4374,10 +4384,12 @@ xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
appendStringInfo(buf, "; rels:");
for (i = 0; i < xlrec->nrels; i++)
{
- RelFileNode rnode = xlrec->xnodes[i];
+ RelFileNode rnode = xlrec->xnodes[i].rnode;
+ ForkNumber forknum = xlrec->xnodes[i].forknum;
- appendStringInfo(buf, " %u/%u/%u",
- rnode.spcNode, rnode.dbNode, rnode.relNode);
+ appendStringInfo(buf, " %u/%u/%u/%u",
+ rnode.spcNode, rnode.dbNode, rnode.relNode,
+ forknum);
}
}
if (xlrec->nsubxacts > 0)
@@ -4402,10 +4414,12 @@ xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
appendStringInfo(buf, "; rels:");
for (i = 0; i < xlrec->nrels; i++)
{
- RelFileNode rnode = xlrec->xnodes[i];
+ RelFileNode rnode = xlrec->xnodes[i].rnode;
+ ForkNumber forknum = xlrec->xnodes[i].forknum;
- appendStringInfo(buf, " %u/%u/%u",
- rnode.spcNode, rnode.dbNode, rnode.relNode);
+ appendStringInfo(buf, " %u/%u/%u/%u",
+ rnode.spcNode, rnode.dbNode, rnode.relNode,
+ forknum);
}
}
if (xlrec->nsubxacts > 0)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 72e531d3dc3..709836f2be7 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.316 2008/07/13 20:45:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.317 2008/08/11 11:05:10 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1034,8 +1034,7 @@ XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites,
/*
* The page needs to be backed up, so set up *bkpb
*/
- bkpb->node = BufferGetFileNode(rdata->buffer);
- bkpb->block = BufferGetBlockNumber(rdata->buffer);
+ BufferGetTag(rdata->buffer, &bkpb->node, &bkpb->fork, &bkpb->block);
if (rdata->buffer_std)
{
@@ -2855,7 +2854,8 @@ RestoreBkpBlocks(XLogRecord *record, XLogRecPtr lsn)
memcpy(&bkpb, blk, sizeof(BkpBlock));
blk += sizeof(BkpBlock);
- buffer = XLogReadBuffer(bkpb.node, bkpb.block, true);
+ buffer = XLogReadBufferWithFork(bkpb.node, bkpb.fork, bkpb.block,
+ true);
Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer);
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 3e2d5046da6..59124e349e4 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.57 2008/07/13 20:45:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.58 2008/08/11 11:05:10 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -37,6 +37,7 @@
typedef struct xl_invalid_page_key
{
RelFileNode node; /* the relation */
+ ForkNumber forkno; /* the fork number */
BlockNumber blkno; /* the page */
} xl_invalid_page_key;
@@ -51,7 +52,8 @@ static HTAB *invalid_page_tab = NULL;
/* Log a reference to an invalid page */
static void
-log_invalid_page(RelFileNode node, BlockNumber blkno, bool present)
+log_invalid_page(RelFileNode node, ForkNumber forkno, BlockNumber blkno,
+ bool present)
{
xl_invalid_page_key key;
xl_invalid_page *hentry;
@@ -63,11 +65,11 @@ log_invalid_page(RelFileNode node, BlockNumber blkno, bool present)
* something about the XLOG record that generated the reference).
*/
if (present)
- elog(DEBUG1, "page %u of relation %u/%u/%u is uninitialized",
- blkno, node.spcNode, node.dbNode, node.relNode);
+ elog(DEBUG1, "page %u of relation %u/%u/%u/%u is uninitialized",
+ blkno, node.spcNode, node.dbNode, node.relNode, forkno);
else
- elog(DEBUG1, "page %u of relation %u/%u/%u does not exist",
- blkno, node.spcNode, node.dbNode, node.relNode);
+ elog(DEBUG1, "page %u of relation %u/%u/%u/%u does not exist",
+ blkno, node.spcNode, node.dbNode, node.relNode, forkno);
if (invalid_page_tab == NULL)
{
@@ -87,6 +89,7 @@ log_invalid_page(RelFileNode node, BlockNumber blkno, bool present)
/* we currently assume xl_invalid_page_key contains no padding */
key.node = node;
+ key.forkno = forkno;
key.blkno = blkno;
hentry = (xl_invalid_page *)
hash_search(invalid_page_tab, (void *) &key, HASH_ENTER, &found);
@@ -104,7 +107,7 @@ log_invalid_page(RelFileNode node, BlockNumber blkno, bool present)
/* Forget any invalid pages >= minblkno, because they've been dropped */
static void
-forget_invalid_pages(RelFileNode node, BlockNumber minblkno)
+forget_invalid_pages(RelFileNode node, ForkNumber forkno, BlockNumber minblkno)
{
HASH_SEQ_STATUS status;
xl_invalid_page *hentry;
@@ -117,11 +120,12 @@ forget_invalid_pages(RelFileNode node, BlockNumber minblkno)
while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
{
if (RelFileNodeEquals(hentry->key.node, node) &&
+ hentry->key.forkno == forkno &&
hentry->key.blkno >= minblkno)
{
- elog(DEBUG2, "page %u of relation %u/%u/%u has been dropped",
+ elog(DEBUG2, "page %u of relation %u/%u/%u/%u has been dropped",
hentry->key.blkno, hentry->key.node.spcNode,
- hentry->key.node.dbNode, hentry->key.node.relNode);
+ hentry->key.node.dbNode, hentry->key.node.relNode, forkno);
if (hash_search(invalid_page_tab,
(void *) &hentry->key,
@@ -224,6 +228,18 @@ XLogCheckInvalidPages(void)
Buffer
XLogReadBuffer(RelFileNode rnode, BlockNumber blkno, bool init)
{
+ return XLogReadBufferWithFork(rnode, MAIN_FORKNUM, blkno, init);
+}
+
+/*
+ * XLogReadBufferWithFork
+ * Like XLogReadBuffer, but for reading other relation forks than
+ * the main one.
+ */
+Buffer
+XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum,
+ BlockNumber blkno, bool init)
+{
BlockNumber lastblock;
Buffer buffer;
SMgrRelation smgr;
@@ -241,21 +257,21 @@ XLogReadBuffer(RelFileNode rnode, BlockNumber blkno, bool init)
* filesystem loses an inode during a crash. Better to write the data
* until we are actually told to delete the file.)
*/
- smgrcreate(smgr, false, true);
+ smgrcreate(smgr, forknum, false, true);
- lastblock = smgrnblocks(smgr);
+ lastblock = smgrnblocks(smgr, forknum);
if (blkno < lastblock)
{
/* page exists in file */
- buffer = ReadBufferWithoutRelcache(rnode, false, blkno, init);
+ buffer = ReadBufferWithoutRelcache(rnode, false, forknum, blkno, init);
}
else
{
/* hm, page doesn't exist in file */
if (!init)
{
- log_invalid_page(rnode, blkno, false);
+ log_invalid_page(rnode, forknum, blkno, false);
return InvalidBuffer;
}
/* OK to extend the file */
@@ -266,7 +282,8 @@ XLogReadBuffer(RelFileNode rnode, BlockNumber blkno, bool init)
{
if (buffer != InvalidBuffer)
ReleaseBuffer(buffer);
- buffer = ReadBufferWithoutRelcache(rnode, false, P_NEW, false);
+ buffer = ReadBufferWithoutRelcache(rnode, false, forknum,
+ P_NEW, false);
lastblock++;
}
Assert(BufferGetBlockNumber(buffer) == blkno);
@@ -282,7 +299,7 @@ XLogReadBuffer(RelFileNode rnode, BlockNumber blkno, bool init)
if (PageIsNew(page))
{
UnlockReleaseBuffer(buffer);
- log_invalid_page(rnode, blkno, true);
+ log_invalid_page(rnode, forknum, blkno, true);
return InvalidBuffer;
}
}
@@ -363,12 +380,9 @@ FreeFakeRelcacheEntry(Relation fakerel)
* any open "invalid-page" records for the relation.
*/
void
-XLogDropRelation(RelFileNode rnode)
+XLogDropRelation(RelFileNode rnode, ForkNumber forknum)
{
- /* Tell smgr to forget about this relation as well */
- smgrclosenode(rnode);
-
- forget_invalid_pages(rnode, 0);
+ forget_invalid_pages(rnode, forknum, 0);
}
/*
@@ -397,7 +411,8 @@ XLogDropDatabase(Oid dbid)
* We need to clean up any open "invalid-page" records for the dropped pages.
*/
void
-XLogTruncateRelation(RelFileNode rnode, BlockNumber nblocks)
+XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum,
+ BlockNumber nblocks)
{
- forget_invalid_pages(rnode, nblocks);
+ forget_invalid_pages(rnode, forkNum, nblocks);
}
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index 30571267b46..eb7b39c86bf 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.77 2008/06/19 00:46:04 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.78 2008/08/11 11:05:10 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,7 +42,8 @@
#include "utils/tqual.h"
-#define OIDCHARS 10 /* max chars printed by %u */
+#define OIDCHARS 10 /* max chars printed by %u */
+#define FORKNUMCHARS 1 /* max chars for a fork number */
/*
@@ -51,7 +52,7 @@
* Result is a palloc'd string.
*/
char *
-relpath(RelFileNode rnode)
+relpath(RelFileNode rnode, ForkNumber forknum)
{
int pathlen;
char *path;
@@ -60,26 +61,38 @@ relpath(RelFileNode rnode)
{
/* Shared system relations live in {datadir}/global */
Assert(rnode.dbNode == 0);
- pathlen = 7 + OIDCHARS + 1;
+ pathlen = 7 + OIDCHARS + 1 + FORKNUMCHARS + 1;
path = (char *) palloc(pathlen);
- snprintf(path, pathlen, "global/%u",
- rnode.relNode);
+ if (forknum != MAIN_FORKNUM)
+ snprintf(path, pathlen, "global/%u_%u",
+ rnode.relNode, forknum);
+ else
+ snprintf(path, pathlen, "global/%u", rnode.relNode);
}
else if (rnode.spcNode == DEFAULTTABLESPACE_OID)
{
/* The default tablespace is {datadir}/base */
- pathlen = 5 + OIDCHARS + 1 + OIDCHARS + 1;
+ pathlen = 5 + OIDCHARS + 1 + OIDCHARS + 1 + FORKNUMCHARS + 1;
path = (char *) palloc(pathlen);
- snprintf(path, pathlen, "base/%u/%u",
- rnode.dbNode, rnode.relNode);
+ if (forknum != MAIN_FORKNUM)
+ snprintf(path, pathlen, "base/%u/%u_%u",
+ rnode.dbNode, rnode.relNode, forknum);
+ else
+ snprintf(path, pathlen, "base/%u/%u",
+ rnode.dbNode, rnode.relNode);
}
else
{
/* All other tablespaces are accessed via symlinks */
- pathlen = 10 + OIDCHARS + 1 + OIDCHARS + 1 + OIDCHARS + 1;
+ pathlen = 10 + OIDCHARS + 1 + OIDCHARS + 1 + OIDCHARS + 1
+ + FORKNUMCHARS + 1;
path = (char *) palloc(pathlen);
- snprintf(path, pathlen, "pg_tblspc/%u/%u/%u",
- rnode.spcNode, rnode.dbNode, rnode.relNode);
+ if (forknum != MAIN_FORKNUM)
+ snprintf(path, pathlen, "pg_tblspc/%u/%u/%u_%u",
+ rnode.spcNode, rnode.dbNode, rnode.relNode, forknum);
+ else
+ snprintf(path, pathlen, "pg_tblspc/%u/%u/%u",
+ rnode.spcNode, rnode.dbNode, rnode.relNode);
}
return path;
}
@@ -431,7 +444,7 @@ GetNewRelFileNode(Oid reltablespace, bool relisshared, Relation pg_class)
rnode.relNode = GetNewObjectId();
/* Check for existing file of same name */
- rpath = relpath(rnode);
+ rpath = relpath(rnode, MAIN_FORKNUM);
fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY, 0);
if (fd >= 0)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index b870d36eb68..c5cea2f67fd 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.336 2008/07/30 19:35:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.337 2008/08/11 11:05:10 heikki Exp $
*
*
* INTERFACE ROUTINES
@@ -292,13 +292,16 @@ heap_create(const char *relname,
shared_relation);
/*
- * have the storage manager create the relation's disk file, if needed.
+ * Have the storage manager create the relation's disk file, if needed.
+ *
+ * We only create storage for the main fork here. The caller is
+ * responsible for creating any additional forks if needed.
*/
if (create_storage)
{
Assert(rel->rd_smgr == NULL);
RelationOpenSmgr(rel);
- smgrcreate(rel->rd_smgr, rel->rd_istemp, false);
+ smgrcreate(rel->rd_smgr, MAIN_FORKNUM, rel->rd_istemp, false);
}
return rel;
@@ -1385,13 +1388,18 @@ heap_drop_with_catalog(Oid relid)
rel = relation_open(relid, AccessExclusiveLock);
/*
- * Schedule unlinking of the relation's physical file at commit.
+ * Schedule unlinking of the relation's physical files at commit.
*/
if (rel->rd_rel->relkind != RELKIND_VIEW &&
rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)
{
+ ForkNumber forknum;
+
RelationOpenSmgr(rel);
- smgrscheduleunlink(rel->rd_smgr, rel->rd_istemp);
+ for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
+ if (smgrexists(rel->rd_smgr, forknum))
+ smgrscheduleunlink(rel->rd_smgr, forknum, rel->rd_istemp);
+ RelationCloseSmgr(rel);
}
/*
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index f06307a7722..abe8d29ac16 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.301 2008/08/10 19:02:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.302 2008/08/11 11:05:10 heikki Exp $
*
*
* INTERFACE ROUTINES
@@ -874,6 +874,7 @@ 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
@@ -892,11 +893,14 @@ index_drop(Oid indexId)
userIndexRelation = index_open(indexId, AccessExclusiveLock);
/*
- * Schedule physical removal of the file
+ * Schedule physical removal of the files
*/
RelationOpenSmgr(userIndexRelation);
- smgrscheduleunlink(userIndexRelation->rd_smgr,
- userIndexRelation->rd_istemp);
+ for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
+ if (smgrexists(userIndexRelation->rd_smgr, forknum))
+ smgrscheduleunlink(userIndexRelation->rd_smgr, forknum,
+ userIndexRelation->rd_istemp);
+ RelationCloseSmgr(userIndexRelation);
/*
* Close and flush the index's relcache entry, to ensure relcache doesn't
@@ -1260,6 +1264,7 @@ setNewRelfilenode(Relation relation, TransactionId freezeXid)
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 ||
@@ -1290,18 +1295,29 @@ setNewRelfilenode(Relation relation, TransactionId freezeXid)
RelationGetRelid(relation));
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
- /* create another storage file. Is it a little ugly ? */
- /* NOTE: any conflict in relfilenode value will be caught here */
+ RelationOpenSmgr(relation);
+
+ /*
+ * ... and create storage for corresponding forks in the new relfilenode.
+ *
+ * NOTE: any conflict in relfilenode value will be caught here
+ */
newrnode = relation->rd_node;
newrnode.relNode = newrelfilenode;
-
srel = smgropen(newrnode);
- smgrcreate(srel, relation->rd_istemp, false);
- smgrclose(srel);
- /* schedule unlinking old relfilenode */
- RelationOpenSmgr(relation);
- smgrscheduleunlink(relation->rd_smgr, relation->rd_istemp);
+ /* Create the main fork, like heap_create() does */
+ smgrcreate(srel, MAIN_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);
/* update the pg_class row */
rd_rel->relfilenode = newrelfilenode;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 58454dcba97..5167a40927a 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.261 2008/07/16 19:33:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.262 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -318,7 +318,8 @@ static void ATExecEnableDisableRule(Relation rel, char *rulename,
char fires_when);
static void ATExecAddInherit(Relation rel, RangeVar *parent);
static void ATExecDropInherit(Relation rel, RangeVar *parent);
-static void copy_relation_data(Relation rel, SMgrRelation dst);
+static void copy_relation_data(SMgrRelation rel, SMgrRelation dst,
+ ForkNumber forkNum, bool istemp);
/* ----------------------------------------------------------------
@@ -6483,6 +6484,7 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace)
Relation pg_class;
HeapTuple tuple;
Form_pg_class rd_rel;
+ ForkNumber forkNum;
/*
* Need lock here in case we are recursing to toast table or index
@@ -6538,26 +6540,42 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace)
elog(ERROR, "cache lookup failed for relation %u", tableOid);
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
- /* create another storage file. Is it a little ugly ? */
- /* NOTE: any conflict in relfilenode value will be caught here */
+ /*
+ * Since we copy the file directly without looking at the shared buffers,
+ * we'd better first flush out any pages of the source relation that are
+ * in shared buffers. We assume no new changes will be made while we are
+ * holding exclusive lock on the rel.
+ */
+ FlushRelationBuffers(rel);
+
+ /* Open old and new relation */
newrnode = rel->rd_node;
newrnode.spcNode = newTableSpace;
-
dstrel = smgropen(newrnode);
- smgrcreate(dstrel, rel->rd_istemp, false);
-
- /* copy relation data to the new physical file */
- copy_relation_data(rel, dstrel);
- /* schedule unlinking old physical file */
RelationOpenSmgr(rel);
- smgrscheduleunlink(rel->rd_smgr, rel->rd_istemp);
/*
- * Now drop smgr references. The source was already dropped by
- * smgrscheduleunlink.
+ * Create and copy all forks of the relation, and schedule unlinking
+ * of old physical files.
+ *
+ * NOTE: any conflict in relfilenode value will be caught in
+ * smgrcreate() below.
*/
+ for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
+ {
+ if (smgrexists(rel->rd_smgr, forkNum))
+ {
+ smgrcreate(dstrel, forkNum, rel->rd_istemp, 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 */
smgrclose(dstrel);
+ RelationCloseSmgr(rel);
/* update the pg_class row */
rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace;
@@ -6584,9 +6602,9 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace)
* Copy data, block by block
*/
static void
-copy_relation_data(Relation rel, SMgrRelation dst)
+copy_relation_data(SMgrRelation src, SMgrRelation dst,
+ ForkNumber forkNum, bool istemp)
{
- SMgrRelation src;
bool use_wal;
BlockNumber nblocks;
BlockNumber blkno;
@@ -6594,37 +6612,27 @@ copy_relation_data(Relation rel, SMgrRelation dst)
Page page = (Page) buf;
/*
- * Since we copy the file directly without looking at the shared buffers,
- * we'd better first flush out any pages of the source relation that are
- * in shared buffers. We assume no new changes will be made while we are
- * holding exclusive lock on the rel.
- */
- FlushRelationBuffers(rel);
-
- /*
* We need to log the copied data in WAL iff WAL archiving is enabled AND
* it's not a temp rel.
*/
- use_wal = XLogArchivingActive() && !rel->rd_istemp;
+ use_wal = XLogArchivingActive() && !istemp;
- nblocks = RelationGetNumberOfBlocks(rel);
- /* RelationGetNumberOfBlocks will certainly have opened rd_smgr */
- src = rel->rd_smgr;
+ nblocks = smgrnblocks(src, forkNum);
for (blkno = 0; blkno < nblocks; blkno++)
{
- smgrread(src, blkno, buf);
+ smgrread(src, forkNum, blkno, buf);
/* XLOG stuff */
if (use_wal)
- log_newpage(&dst->smgr_rnode, blkno, page);
+ log_newpage(&dst->smgr_rnode, forkNum, blkno, page);
/*
* Now write the page. We say isTemp = true even if it's not a temp
* rel, because there's no need for smgr to schedule an fsync for this
* write; we'll do it ourselves below.
*/
- smgrextend(dst, blkno, buf, true);
+ smgrextend(dst, forkNum, blkno, buf, true);
}
/*
@@ -6641,8 +6649,8 @@ copy_relation_data(Relation rel, SMgrRelation dst)
* wouldn't replay our earlier WAL entries. If we do not fsync those pages
* here, they might still not be on disk when the crash occurs.
*/
- if (!rel->rd_istemp)
- smgrimmedsync(dst);
+ if (!istemp)
+ smgrimmedsync(dst, forkNum);
}
/*
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index 21ec395f29d..823c5243797 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.50 2008/05/12 00:00:50 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.51 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -113,6 +113,7 @@
typedef struct
{
RelFileNode rnode;
+ ForkNumber forknum;
BlockNumber segno; /* see md.c for special values */
/* might add a real request-type field later; not needed yet */
} BgWriterRequest;
@@ -990,7 +991,7 @@ RequestCheckpoint(int flags)
* than we have to here.
*/
bool
-ForwardFsyncRequest(RelFileNode rnode, BlockNumber segno)
+ForwardFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
{
BgWriterRequest *request;
@@ -1067,7 +1068,7 @@ AbsorbFsyncRequests(void)
LWLockRelease(BgWriterCommLock);
for (request = requests; n > 0; request++, n--)
- RememberFsyncRequest(request->rnode, request->segno);
+ RememberFsyncRequest(request->rnode, request->forknum, request->segno);
if (requests)
pfree(requests);
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 3c32ddbb7ed..1491aee1635 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.127 2008/06/19 00:46:05 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.128 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -482,8 +482,14 @@ DefineQueryRewrite(char *rulename,
*/
if (RelisBecomingView)
{
+ ForkNumber forknum;
+
RelationOpenSmgr(event_relation);
- smgrscheduleunlink(event_relation->rd_smgr, event_relation->rd_istemp);
+ 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);
}
/* Close rel, but keep lock till commit... */
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 456dc423360..281d23136dd 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.236 2008/08/05 15:09:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.237 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -78,9 +78,10 @@ static bool IsForInput;
static volatile BufferDesc *PinCountWaitBuf = NULL;
-static Buffer ReadBuffer_relcache(Relation reln, BlockNumber blockNum,
- bool zeroPage, BufferAccessStrategy strategy);
-static Buffer ReadBuffer_common(SMgrRelation reln, bool isLocalBuf, BlockNumber blockNum,
+static Buffer ReadBuffer_relcache(Relation reln, ForkNumber forkNum,
+ BlockNumber blockNum, bool zeroPage, BufferAccessStrategy strategy);
+static Buffer ReadBuffer_common(SMgrRelation reln, bool isLocalBuf,
+ ForkNumber forkNum, BlockNumber blockNum,
bool zeroPage, BufferAccessStrategy strategy, bool *hit);
static bool PinBuffer(volatile BufferDesc *buf, BufferAccessStrategy strategy);
static void PinBuffer_Locked(volatile BufferDesc *buf);
@@ -92,7 +93,8 @@ static bool StartBufferIO(volatile BufferDesc *buf, bool forInput);
static void TerminateBufferIO(volatile BufferDesc *buf, bool clear_dirty,
int set_flag_bits);
static void buffer_write_error_callback(void *arg);
-static volatile BufferDesc *BufferAlloc(SMgrRelation smgr, BlockNumber blockNum,
+static volatile BufferDesc *BufferAlloc(SMgrRelation smgr, ForkNumber forkNum,
+ BlockNumber blockNum,
BufferAccessStrategy strategy,
bool *foundPtr);
static void FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln);
@@ -117,7 +119,17 @@ static void AtProcExit_Buffers(int code, Datum arg);
Buffer
ReadBuffer(Relation reln, BlockNumber blockNum)
{
- return ReadBuffer_relcache(reln, blockNum, false, NULL);
+ return ReadBuffer_relcache(reln, MAIN_FORKNUM, blockNum, false, NULL);
+}
+
+/*
+ * ReadBufferWithFork -- same as ReadBuffer, but for accessing relation
+ * forks other than MAIN_FORKNUM.
+ */
+Buffer
+ReadBufferWithFork(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
+{
+ return ReadBuffer_relcache(reln, forkNum, blockNum, false, NULL);
}
/*
@@ -128,7 +140,7 @@ Buffer
ReadBufferWithStrategy(Relation reln, BlockNumber blockNum,
BufferAccessStrategy strategy)
{
- return ReadBuffer_relcache(reln, blockNum, false, strategy);
+ return ReadBuffer_relcache(reln, MAIN_FORKNUM, blockNum, false, strategy);
}
/*
@@ -143,32 +155,32 @@ ReadBufferWithStrategy(Relation reln, BlockNumber blockNum,
* the page is modified and written out. P_NEW is OK, though.
*/
Buffer
-ReadOrZeroBuffer(Relation reln, BlockNumber blockNum)
+ReadOrZeroBuffer(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
{
- return ReadBuffer_relcache(reln, blockNum, true, NULL);
+ return ReadBuffer_relcache(reln, forkNum, blockNum, true, NULL);
}
/*
- * ReadBufferWithoutRelcache -- like ReadBuffer, but doesn't require a
+ * ReadBufferWithoutRelcache -- like ReadBuffer, but doesn't require a
* relcache entry for the relation. If zeroPage is true, this behaves
* like ReadOrZeroBuffer rather than ReadBuffer.
*/
Buffer
-ReadBufferWithoutRelcache(RelFileNode rnode, bool isTemp,
- BlockNumber blockNum, bool zeroPage)
+ReadBufferWithoutRelcache(RelFileNode rnode, bool isTemp,
+ ForkNumber forkNum, BlockNumber blockNum, bool zeroPage)
{
bool hit;
SMgrRelation smgr = smgropen(rnode);
- return ReadBuffer_common(smgr, isTemp, blockNum, zeroPage, NULL, &hit);
+ return ReadBuffer_common(smgr, isTemp, forkNum, blockNum, zeroPage, NULL, &hit);
}
/*
- * ReadBuffer_relcache -- common logic for ReadBuffer-variants that
+ * ReadBuffer_relcache -- common logic for ReadBuffer-variants that
* operate on a Relation.
*/
static Buffer
-ReadBuffer_relcache(Relation reln, BlockNumber blockNum,
+ReadBuffer_relcache(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
bool zeroPage, BufferAccessStrategy strategy)
{
bool hit;
@@ -182,7 +194,7 @@ ReadBuffer_relcache(Relation reln, BlockNumber blockNum,
* hit or miss.
*/
pgstat_count_buffer_read(reln);
- buf = ReadBuffer_common(reln->rd_smgr, reln->rd_istemp, blockNum,
+ buf = ReadBuffer_common(reln->rd_smgr, reln->rd_istemp, forkNum, blockNum,
zeroPage, strategy, &hit);
if (hit)
pgstat_count_buffer_hit(reln);
@@ -195,8 +207,9 @@ ReadBuffer_relcache(Relation reln, BlockNumber blockNum,
* *hit is set to true if the request was satisfied from shared buffer cache.
*/
static Buffer
-ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, BlockNumber blockNum,
- bool zeroPage, BufferAccessStrategy strategy, bool *hit)
+ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, ForkNumber forkNum,
+ BlockNumber blockNum, bool zeroPage,
+ BufferAccessStrategy strategy, bool *hit)
{
volatile BufferDesc *bufHdr;
Block bufBlock;
@@ -212,7 +225,7 @@ ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, BlockNumber blockNum,
/* Substitute proper block number if caller asked for P_NEW */
if (isExtend)
- blockNum = smgrnblocks(smgr);
+ blockNum = smgrnblocks(smgr, forkNum);
TRACE_POSTGRESQL_BUFFER_READ_START(blockNum, smgr->smgr_rnode.spcNode,
smgr->smgr_rnode.dbNode, smgr->smgr_rnode.relNode, isLocalBuf);
@@ -220,7 +233,7 @@ ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, BlockNumber blockNum,
if (isLocalBuf)
{
ReadLocalBufferCount++;
- bufHdr = LocalBufferAlloc(smgr, blockNum, &found);
+ bufHdr = LocalBufferAlloc(smgr, forkNum, blockNum, &found);
if (found)
{
LocalBufferHitCount++;
@@ -239,7 +252,7 @@ ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, BlockNumber blockNum,
* lookup the buffer. IO_IN_PROGRESS is set if the requested block is
* not currently in memory.
*/
- bufHdr = BufferAlloc(smgr, blockNum, strategy, &found);
+ bufHdr = BufferAlloc(smgr, forkNum, blockNum, strategy, &found);
if (found)
{
BufferHitCount++;
@@ -341,7 +354,7 @@ ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, BlockNumber blockNum,
{
/* new buffers are zero-filled */
MemSet((char *) bufBlock, 0, BLCKSZ);
- smgrextend(smgr, blockNum, (char *) bufBlock, isLocalBuf);
+ smgrextend(smgr, forkNum, blockNum, (char *) bufBlock, isLocalBuf);
}
else
{
@@ -353,7 +366,7 @@ ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, BlockNumber blockNum,
MemSet((char *) bufBlock, 0, BLCKSZ);
else
{
- smgrread(smgr, blockNum, (char *) bufBlock);
+ smgrread(smgr, forkNum, blockNum, (char *) bufBlock);
/* check for garbage data */
if (!PageHeaderIsValid((PageHeader) bufBlock))
@@ -363,7 +376,7 @@ ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, BlockNumber blockNum,
ereport(WARNING,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg("invalid page header in block %u of relation %u/%u/%u; zeroing out page",
- blockNum,
+ blockNum,
smgr->smgr_rnode.spcNode,
smgr->smgr_rnode.dbNode,
smgr->smgr_rnode.relNode)));
@@ -421,7 +434,7 @@ ReadBuffer_common(SMgrRelation smgr, bool isLocalBuf, BlockNumber blockNum,
* No locks are held either at entry or exit.
*/
static volatile BufferDesc *
-BufferAlloc(SMgrRelation smgr,
+BufferAlloc(SMgrRelation smgr, ForkNumber forkNum,
BlockNumber blockNum,
BufferAccessStrategy strategy,
bool *foundPtr)
@@ -438,7 +451,7 @@ BufferAlloc(SMgrRelation smgr,
bool valid;
/* create a tag so we can lookup the buffer */
- INIT_BUFFERTAG(newTag, smgr->smgr_rnode, blockNum);
+ INIT_BUFFERTAG(newTag, smgr->smgr_rnode, forkNum, blockNum);
/* determine its hash code and partition lock ID */
newHash = BufTableHashCode(&newTag);
@@ -903,6 +916,7 @@ ReleaseAndReadBuffer(Buffer buffer,
Relation relation,
BlockNumber blockNum)
{
+ ForkNumber forkNum = MAIN_FORKNUM;
volatile BufferDesc *bufHdr;
if (BufferIsValid(buffer))
@@ -912,7 +926,8 @@ ReleaseAndReadBuffer(Buffer buffer,
Assert(LocalRefCount[-buffer - 1] > 0);
bufHdr = &LocalBufferDescriptors[-buffer - 1];
if (bufHdr->tag.blockNum == blockNum &&
- RelFileNodeEquals(bufHdr->tag.rnode, relation->rd_node))
+ RelFileNodeEquals(bufHdr->tag.rnode, relation->rd_node) &&
+ bufHdr->tag.forkNum == forkNum)
return buffer;
ResourceOwnerForgetBuffer(CurrentResourceOwner, buffer);
LocalRefCount[-buffer - 1]--;
@@ -923,7 +938,8 @@ ReleaseAndReadBuffer(Buffer buffer,
bufHdr = &BufferDescriptors[buffer - 1];
/* we have pin, so it's ok to examine tag without spinlock */
if (bufHdr->tag.blockNum == blockNum &&
- RelFileNodeEquals(bufHdr->tag.rnode, relation->rd_node))
+ RelFileNodeEquals(bufHdr->tag.rnode, relation->rd_node) &&
+ bufHdr->tag.forkNum == forkNum)
return buffer;
UnpinBuffer(bufHdr, true);
}
@@ -1734,23 +1750,28 @@ BufferGetBlockNumber(Buffer buffer)
}
/*
- * BufferGetFileNode
- * Returns the relation ID (RelFileNode) associated with a buffer.
- *
- * This should make the same checks as BufferGetBlockNumber, but since the
- * two are generally called together, we don't bother.
+ * BufferGetTag
+ * Returns the relfilenode, fork number and block number associated with
+ * a buffer.
*/
-RelFileNode
-BufferGetFileNode(Buffer buffer)
+void
+BufferGetTag(Buffer buffer, RelFileNode *rnode, ForkNumber *forknum,
+ BlockNumber *blknum)
{
volatile BufferDesc *bufHdr;
+ /* Do the same checks as BufferGetBlockNumber. */
+ Assert(BufferIsPinned(buffer));
+
if (BufferIsLocal(buffer))
bufHdr = &(LocalBufferDescriptors[-buffer - 1]);
else
bufHdr = &BufferDescriptors[buffer - 1];
- return bufHdr->tag.rnode;
+ /* pinned, so OK to read tag without spinlock */
+ *rnode = bufHdr->tag.rnode;
+ *forknum = bufHdr->tag.forkNum;
+ *blknum = bufHdr->tag.blockNum;
}
/*
@@ -1820,6 +1841,7 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
UnlockBufHdr(buf);
smgrwrite(reln,
+ buf->tag.forkNum,
buf->tag.blockNum,
(char *) BufHdrGetBlock(buf),
false);
@@ -1849,7 +1871,7 @@ RelationGetNumberOfBlocks(Relation relation)
/* Open it at the smgr level if not already done */
RelationOpenSmgr(relation);
- return smgrnblocks(relation->rd_smgr);
+ return smgrnblocks(relation->rd_smgr, MAIN_FORKNUM);
}
/*
@@ -1869,7 +1891,7 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
rel->rd_targblock = InvalidBlockNumber;
/* Do the real work */
- smgrtruncate(rel->rd_smgr, nblocks, rel->rd_istemp);
+ smgrtruncate(rel->rd_smgr, MAIN_FORKNUM, nblocks, rel->rd_istemp);
}
/* ---------------------------------------------------------------------
@@ -1899,14 +1921,14 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
* --------------------------------------------------------------------
*/
void
-DropRelFileNodeBuffers(RelFileNode rnode, bool istemp,
+DropRelFileNodeBuffers(RelFileNode rnode, ForkNumber forkNum, bool istemp,
BlockNumber firstDelBlock)
{
int i;
if (istemp)
{
- DropRelFileNodeLocalBuffers(rnode, firstDelBlock);
+ DropRelFileNodeLocalBuffers(rnode, forkNum, firstDelBlock);
return;
}
@@ -1916,6 +1938,7 @@ DropRelFileNodeBuffers(RelFileNode rnode, bool istemp,
LockBufHdr(bufHdr);
if (RelFileNodeEquals(bufHdr->tag.rnode, rnode) &&
+ bufHdr->tag.forkNum == forkNum &&
bufHdr->tag.blockNum >= firstDelBlock)
InvalidateBuffer(bufHdr); /* releases spinlock */
else
@@ -2055,6 +2078,7 @@ FlushRelationBuffers(Relation rel)
error_context_stack = &errcontext;
smgrwrite(rel->rd_smgr,
+ bufHdr->tag.forkNum,
bufHdr->tag.blockNum,
(char *) LocalBufHdrGetBlock(bufHdr),
true);
diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c
index ae5f3049a5f..386026f14dd 100644
--- a/src/backend/storage/buffer/localbuf.c
+++ b/src/backend/storage/buffer/localbuf.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.80 2008/06/12 09:12:31 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.81 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -61,7 +61,8 @@ static Block GetLocalBufferStorage(void);
* (hence, usage_count is always advanced).
*/
BufferDesc *
-LocalBufferAlloc(SMgrRelation smgr, BlockNumber blockNum, bool *foundPtr)
+LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum,
+ bool *foundPtr)
{
BufferTag newTag; /* identity of requested block */
LocalBufferLookupEnt *hresult;
@@ -70,7 +71,7 @@ LocalBufferAlloc(SMgrRelation smgr, BlockNumber blockNum, bool *foundPtr)
int trycounter;
bool found;
- INIT_BUFFERTAG(newTag, smgr->smgr_rnode, blockNum);
+ INIT_BUFFERTAG(newTag, smgr->smgr_rnode, forkNum, blockNum);
/* Initialize local buffers if first request in this session */
if (LocalBufHash == NULL)
@@ -162,6 +163,7 @@ LocalBufferAlloc(SMgrRelation smgr, BlockNumber blockNum, bool *foundPtr)
/* And write... */
smgrwrite(oreln,
+ bufHdr->tag.forkNum,
bufHdr->tag.blockNum,
(char *) LocalBufHdrGetBlock(bufHdr),
true);
@@ -250,7 +252,8 @@ MarkLocalBufferDirty(Buffer buffer)
* See DropRelFileNodeBuffers in bufmgr.c for more notes.
*/
void
-DropRelFileNodeLocalBuffers(RelFileNode rnode, BlockNumber firstDelBlock)
+DropRelFileNodeLocalBuffers(RelFileNode rnode, ForkNumber forkNum,
+ BlockNumber firstDelBlock)
{
int i;
@@ -261,6 +264,7 @@ DropRelFileNodeLocalBuffers(RelFileNode rnode, BlockNumber firstDelBlock)
if ((bufHdr->flags & BM_TAG_VALID) &&
RelFileNodeEquals(bufHdr->tag.rnode, rnode) &&
+ bufHdr->tag.forkNum == forkNum &&
bufHdr->tag.blockNum >= firstDelBlock)
{
if (LocalRefCount[i] != 0)
diff --git a/src/backend/storage/smgr/README b/src/backend/storage/smgr/README
index 5d79ef54161..cc798533f2e 100644
--- a/src/backend/storage/smgr/README
+++ b/src/backend/storage/smgr/README
@@ -1,4 +1,4 @@
-$PostgreSQL: pgsql/src/backend/storage/smgr/README,v 1.5 2008/03/21 13:23:28 momjian Exp $
+$PostgreSQL: pgsql/src/backend/storage/smgr/README,v 1.6 2008/08/11 11:05:11 heikki Exp $
Storage Manager
===============
@@ -32,3 +32,20 @@ The files in this directory, and their contents, are
md.c The magnetic disk storage manager.
Note that md.c in turn relies on src/backend/storage/file/fd.c.
+
+Relation Forks
+==============
+
+Since 8.4, a single smgr relation can be comprised of multiple physical
+files, called relation forks. This allows storing additional metadata like
+Free Space information in additional forks, which can be grown and truncated
+independently of the main data file, while still treating it all as a single
+physical relation in system catalogs.
+
+It is assumed that the main fork, fork number 0 or MAIN_FORKNUM, always
+exists. Fork numbers are assigned in src/include/storage/relfilenode.h.
+Functions in smgr.c and md.c take an extra fork number argument, in addition
+to relfilenode and block number, to identify which relation fork you want to
+access. Since most code wants to access the main fork, a shortcut version of
+ReadBuffer that accesses MAIN_FORKNUM is provided in the buffer manager for
+convenience.
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index acd669f1f74..a76fea454dc 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/smgr/md.c,v 1.138 2008/05/02 01:08:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/smgr/md.c,v 1.139 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,6 +23,7 @@
#include "postmaster/bgwriter.h"
#include "storage/fd.h"
#include "storage/bufmgr.h"
+#include "storage/relfilenode.h"
#include "storage/smgr.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
@@ -118,6 +119,7 @@ static MemoryContext MdCxt; /* context for all md.c allocations */
typedef struct
{
RelFileNode rnode; /* the targeted relation */
+ ForkNumber forknum;
BlockNumber segno; /* which segment */
} PendingOperationTag;
@@ -151,15 +153,18 @@ typedef enum /* behavior for mdopen & _mdfd_getseg */
} ExtensionBehavior;
/* local routines */
-static MdfdVec *mdopen(SMgrRelation reln, ExtensionBehavior behavior);
-static void register_dirty_segment(SMgrRelation reln, MdfdVec *seg);
+static MdfdVec *mdopen(SMgrRelation reln, ForkNumber forknum,
+ ExtensionBehavior behavior);
+static void register_dirty_segment(SMgrRelation reln, ForkNumber forknum,
+ MdfdVec *seg);
static void register_unlink(RelFileNode rnode);
static MdfdVec *_fdvec_alloc(void);
-static MdfdVec *_mdfd_openseg(SMgrRelation reln, BlockNumber segno,
- int oflags);
-static MdfdVec *_mdfd_getseg(SMgrRelation reln, BlockNumber blkno,
- bool isTemp, ExtensionBehavior behavior);
-static BlockNumber _mdnblocks(SMgrRelation reln, MdfdVec *seg);
+static MdfdVec *_mdfd_openseg(SMgrRelation reln, ForkNumber forkno,
+ BlockNumber segno, int oflags);
+static MdfdVec *_mdfd_getseg(SMgrRelation reln, ForkNumber forkno,
+ BlockNumber blkno, bool isTemp, ExtensionBehavior behavior);
+static BlockNumber _mdnblocks(SMgrRelation reln, ForkNumber forknum,
+ MdfdVec *seg);
/*
@@ -198,22 +203,39 @@ mdinit(void)
}
/*
+ * mdexists() -- Does the physical file exist?
+ *
+ * Note: this will return true for lingering files, with pending deletions
+ */
+bool
+mdexists(SMgrRelation reln, ForkNumber forkNum)
+{
+ /*
+ * Close it first, to ensure that we notice if the fork has been
+ * unlinked since we opened it.
+ */
+ mdclose(reln, forkNum);
+
+ return (mdopen(reln, forkNum, EXTENSION_RETURN_NULL) != NULL);
+}
+
+/*
* mdcreate() -- Create a new relation on magnetic disk.
*
* If isRedo is true, it's okay for the relation to exist already.
*/
void
-mdcreate(SMgrRelation reln, bool isRedo)
+mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
{
char *path;
File fd;
- if (isRedo && reln->md_fd != NULL)
+ if (isRedo && reln->md_fd[forkNum] != NULL)
return; /* created and opened already... */
- Assert(reln->md_fd == NULL);
+ Assert(reln->md_fd[forkNum] == NULL);
- path = relpath(reln->smgr_rnode);
+ path = relpath(reln->smgr_rnode, forkNum);
fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600);
@@ -236,20 +258,21 @@ mdcreate(SMgrRelation reln, bool isRedo)
errno = save_errno;
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not create relation %u/%u/%u: %m",
+ errmsg("could not create relation %u/%u/%u/%u: %m",
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
- reln->smgr_rnode.relNode)));
+ reln->smgr_rnode.relNode,
+ forkNum)));
}
}
pfree(path);
- reln->md_fd = _fdvec_alloc();
+ reln->md_fd[forkNum] = _fdvec_alloc();
- reln->md_fd->mdfd_vfd = fd;
- reln->md_fd->mdfd_segno = 0;
- reln->md_fd->mdfd_chain = NULL;
+ reln->md_fd[forkNum]->mdfd_vfd = fd;
+ reln->md_fd[forkNum]->mdfd_segno = 0;
+ reln->md_fd[forkNum]->mdfd_chain = NULL;
}
/*
@@ -285,7 +308,7 @@ mdcreate(SMgrRelation reln, bool isRedo)
* we are usually not in a transaction anymore when this is called.
*/
void
-mdunlink(RelFileNode rnode, bool isRedo)
+mdunlink(RelFileNode rnode, ForkNumber forkNum, bool isRedo)
{
char *path;
int ret;
@@ -294,14 +317,14 @@ mdunlink(RelFileNode rnode, bool isRedo)
* We have to clean out any pending fsync requests for the doomed
* relation, else the next mdsync() will fail.
*/
- ForgetRelationFsyncRequests(rnode);
+ ForgetRelationFsyncRequests(rnode, forkNum);
- path = relpath(rnode);
+ path = relpath(rnode, forkNum);
/*
* Delete or truncate the first segment.
*/
- if (isRedo)
+ if (isRedo || forkNum != MAIN_FORKNUM)
ret = unlink(path);
else
{
@@ -326,10 +349,11 @@ mdunlink(RelFileNode rnode, bool isRedo)
if (!isRedo || errno != ENOENT)
ereport(WARNING,
(errcode_for_file_access(),
- errmsg("could not remove relation %u/%u/%u: %m",
+ errmsg("could not remove relation %u/%u/%u/%u: %m",
rnode.spcNode,
rnode.dbNode,
- rnode.relNode)));
+ rnode.relNode,
+ forkNum)));
}
/*
@@ -353,11 +377,12 @@ mdunlink(RelFileNode rnode, bool isRedo)
if (errno != ENOENT)
ereport(WARNING,
(errcode_for_file_access(),
- errmsg("could not remove segment %u of relation %u/%u/%u: %m",
+ errmsg("could not remove segment %u of relation %u/%u/%u/%u: %m",
segno,
rnode.spcNode,
rnode.dbNode,
- rnode.relNode)));
+ rnode.relNode,
+ forkNum)));
break;
}
}
@@ -367,7 +392,7 @@ mdunlink(RelFileNode rnode, bool isRedo)
pfree(path);
/* Register request to unlink first segment later */
- if (!isRedo)
+ if (!isRedo && forkNum == MAIN_FORKNUM)
register_unlink(rnode);
}
@@ -381,7 +406,8 @@ mdunlink(RelFileNode rnode, bool isRedo)
* causes intervening file space to become filled with zeroes.
*/
void
-mdextend(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
+mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+ char *buffer, bool isTemp)
{
off_t seekpos;
int nbytes;
@@ -389,7 +415,7 @@ mdextend(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
/* This assert is too expensive to have on normally ... */
#ifdef CHECK_WRITE_VS_EXTEND
- Assert(blocknum >= mdnblocks(reln));
+ Assert(blocknum >= mdnblocks(reln, forknum));
#endif
/*
@@ -400,13 +426,14 @@ mdextend(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
if (blocknum == InvalidBlockNumber)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
- errmsg("cannot extend relation %u/%u/%u beyond %u blocks",
+ errmsg("cannot extend relation %u/%u/%u/%u beyond %u blocks",
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode,
+ forknum,
InvalidBlockNumber)));
- v = _mdfd_getseg(reln, blocknum, isTemp, EXTENSION_CREATE);
+ v = _mdfd_getseg(reln, forknum, blocknum, isTemp, EXTENSION_CREATE);
seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
@@ -423,37 +450,40 @@ mdextend(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not seek to block %u of relation %u/%u/%u: %m",
+ errmsg("could not seek to block %u of relation %u/%u/%u/%u: %m",
blocknum,
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
- reln->smgr_rnode.relNode)));
+ reln->smgr_rnode.relNode,
+ forknum)));
if ((nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ)) != BLCKSZ)
{
if (nbytes < 0)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not extend relation %u/%u/%u: %m",
+ errmsg("could not extend relation %u/%u/%u/%u: %m",
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
- reln->smgr_rnode.relNode),
+ reln->smgr_rnode.relNode,
+ forknum),
errhint("Check free disk space.")));
/* short write: complain appropriately */
ereport(ERROR,
(errcode(ERRCODE_DISK_FULL),
- errmsg("could not extend relation %u/%u/%u: wrote only %d of %d bytes at block %u",
+ errmsg("could not extend relation %u/%u/%u/%u: wrote only %d of %d bytes at block %u",
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode,
+ forknum,
nbytes, BLCKSZ, blocknum),
errhint("Check free disk space.")));
}
if (!isTemp)
- register_dirty_segment(reln, v);
+ register_dirty_segment(reln, forknum, v);
- Assert(_mdnblocks(reln, v) <= ((BlockNumber) RELSEG_SIZE));
+ Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
}
/*
@@ -467,17 +497,17 @@ mdextend(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
* invent one out of whole cloth.
*/
static MdfdVec *
-mdopen(SMgrRelation reln, ExtensionBehavior behavior)
+mdopen(SMgrRelation reln, ForkNumber forknum, ExtensionBehavior behavior)
{
MdfdVec *mdfd;
char *path;
File fd;
/* No work if already open */
- if (reln->md_fd)
- return reln->md_fd;
+ if (reln->md_fd[forknum])
+ return reln->md_fd[forknum];
- path = relpath(reln->smgr_rnode);
+ path = relpath(reln->smgr_rnode, forknum);
fd = PathNameOpenFile(path, O_RDWR | PG_BINARY, 0600);
@@ -499,21 +529,22 @@ mdopen(SMgrRelation reln, ExtensionBehavior behavior)
return NULL;
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not open relation %u/%u/%u: %m",
+ errmsg("could not open relation %u/%u/%u/%u: %m",
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
- reln->smgr_rnode.relNode)));
+ reln->smgr_rnode.relNode,
+ forknum)));
}
}
pfree(path);
- reln->md_fd = mdfd = _fdvec_alloc();
+ reln->md_fd[forknum] = mdfd = _fdvec_alloc();
mdfd->mdfd_vfd = fd;
mdfd->mdfd_segno = 0;
mdfd->mdfd_chain = NULL;
- Assert(_mdnblocks(reln, mdfd) <= ((BlockNumber) RELSEG_SIZE));
+ Assert(_mdnblocks(reln, forknum, mdfd) <= ((BlockNumber) RELSEG_SIZE));
return mdfd;
}
@@ -522,15 +553,15 @@ mdopen(SMgrRelation reln, ExtensionBehavior behavior)
* mdclose() -- Close the specified relation, if it isn't closed already.
*/
void
-mdclose(SMgrRelation reln)
+mdclose(SMgrRelation reln, ForkNumber forknum)
{
- MdfdVec *v = reln->md_fd;
+ MdfdVec *v = reln->md_fd[forknum];
/* No work if already closed */
if (v == NULL)
return;
- reln->md_fd = NULL; /* prevent dangling pointer after error */
+ reln->md_fd[forknum] = NULL; /* prevent dangling pointer after error */
while (v != NULL)
{
@@ -549,13 +580,14 @@ mdclose(SMgrRelation reln)
* mdread() -- Read the specified block from a relation.
*/
void
-mdread(SMgrRelation reln, BlockNumber blocknum, char *buffer)
+mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+ char *buffer)
{
off_t seekpos;
int nbytes;
MdfdVec *v;
- v = _mdfd_getseg(reln, blocknum, false, EXTENSION_FAIL);
+ v = _mdfd_getseg(reln, forknum, blocknum, false, EXTENSION_FAIL);
seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
@@ -563,22 +595,24 @@ mdread(SMgrRelation reln, BlockNumber blocknum, char *buffer)
if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not seek to block %u of relation %u/%u/%u: %m",
+ errmsg("could not seek to block %u of relation %u/%u/%u/%u: %m",
blocknum,
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
- reln->smgr_rnode.relNode)));
+ reln->smgr_rnode.relNode,
+ forknum)));
if ((nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ)) != BLCKSZ)
{
if (nbytes < 0)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not read block %u of relation %u/%u/%u: %m",
+ errmsg("could not read block %u of relation %u/%u/%u/%u: %m",
blocknum,
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
- reln->smgr_rnode.relNode)));
+ reln->smgr_rnode.relNode,
+ forknum)));
/*
* Short read: we are at or past EOF, or we read a partial block at
@@ -593,11 +627,12 @@ mdread(SMgrRelation reln, BlockNumber blocknum, char *buffer)
else
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
- errmsg("could not read block %u of relation %u/%u/%u: read only %d of %d bytes",
+ errmsg("could not read block %u of relation %u/%u/%u/%u: read only %d of %d bytes",
blocknum,
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode,
+ forknum,
nbytes, BLCKSZ)));
}
}
@@ -610,7 +645,8 @@ mdread(SMgrRelation reln, BlockNumber blocknum, char *buffer)
* use mdextend().
*/
void
-mdwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
+mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+ char *buffer, bool isTemp)
{
off_t seekpos;
int nbytes;
@@ -618,10 +654,10 @@ mdwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
/* This assert is too expensive to have on normally ... */
#ifdef CHECK_WRITE_VS_EXTEND
- Assert(blocknum < mdnblocks(reln));
+ Assert(blocknum < mdnblocks(reln, forknum));
#endif
- v = _mdfd_getseg(reln, blocknum, isTemp, EXTENSION_FAIL);
+ v = _mdfd_getseg(reln, forknum, blocknum, isTemp, EXTENSION_FAIL);
seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
@@ -629,36 +665,39 @@ mdwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not seek to block %u of relation %u/%u/%u: %m",
+ errmsg("could not seek to block %u of relation %u/%u/%u/%u: %m",
blocknum,
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
- reln->smgr_rnode.relNode)));
+ reln->smgr_rnode.relNode,
+ forknum)));
if ((nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ)) != BLCKSZ)
{
if (nbytes < 0)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not write block %u of relation %u/%u/%u: %m",
+ errmsg("could not write block %u of relation %u/%u/%u/%u: %m",
blocknum,
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
- reln->smgr_rnode.relNode)));
+ reln->smgr_rnode.relNode,
+ forknum)));
/* short write: complain appropriately */
ereport(ERROR,
(errcode(ERRCODE_DISK_FULL),
- errmsg("could not write block %u of relation %u/%u/%u: wrote only %d of %d bytes",
+ errmsg("could not write block %u of relation %u/%u/%u/%u: wrote only %d of %d bytes",
blocknum,
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode,
+ forknum,
nbytes, BLCKSZ),
errhint("Check free disk space.")));
}
if (!isTemp)
- register_dirty_segment(reln, v);
+ register_dirty_segment(reln, forknum, v);
}
/*
@@ -670,9 +709,9 @@ mdwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
* are present in the chain.
*/
BlockNumber
-mdnblocks(SMgrRelation reln)
+mdnblocks(SMgrRelation reln, ForkNumber forknum)
{
- MdfdVec *v = mdopen(reln, EXTENSION_FAIL);
+ MdfdVec *v = mdopen(reln, forknum, EXTENSION_FAIL);
BlockNumber nblocks;
BlockNumber segno = 0;
@@ -696,7 +735,7 @@ mdnblocks(SMgrRelation reln)
for (;;)
{
- nblocks = _mdnblocks(reln, v);
+ nblocks = _mdnblocks(reln, forknum, v);
if (nblocks > ((BlockNumber) RELSEG_SIZE))
elog(FATAL, "segment too big");
if (nblocks < ((BlockNumber) RELSEG_SIZE))
@@ -715,15 +754,16 @@ mdnblocks(SMgrRelation reln)
* RELSEG_SIZE. While perhaps not strictly necessary, this keeps
* the logic simple.
*/
- v->mdfd_chain = _mdfd_openseg(reln, segno, O_CREAT);
+ v->mdfd_chain = _mdfd_openseg(reln, forknum, segno, O_CREAT);
if (v->mdfd_chain == NULL)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not open segment %u of relation %u/%u/%u: %m",
+ errmsg("could not open segment %u of relation %u/%u/%u/%u: %m",
segno,
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
- reln->smgr_rnode.relNode)));
+ reln->smgr_rnode.relNode,
+ forknum)));
}
v = v->mdfd_chain;
@@ -734,7 +774,8 @@ mdnblocks(SMgrRelation reln)
* mdtruncate() -- Truncate relation to specified number of blocks.
*/
void
-mdtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
+mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks,
+ bool isTemp)
{
MdfdVec *v;
BlockNumber curnblk;
@@ -744,23 +785,24 @@ mdtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
* NOTE: mdnblocks makes sure we have opened all active segments, so that
* truncation loop will get them all!
*/
- curnblk = mdnblocks(reln);
+ curnblk = mdnblocks(reln, forknum);
if (nblocks > curnblk)
{
/* Bogus request ... but no complaint if InRecovery */
if (InRecovery)
return;
ereport(ERROR,
- (errmsg("could not truncate relation %u/%u/%u to %u blocks: it's only %u blocks now",
+ (errmsg("could not truncate relation %u/%u/%u/%u to %u blocks: it's only %u blocks now",
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode,
+ forknum,
nblocks, curnblk)));
}
if (nblocks == curnblk)
return; /* no work */
- v = mdopen(reln, EXTENSION_FAIL);
+ v = mdopen(reln, forknum, EXTENSION_FAIL);
priorblocks = 0;
while (v != NULL)
@@ -777,15 +819,16 @@ mdtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
if (FileTruncate(v->mdfd_vfd, 0) < 0)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not truncate relation %u/%u/%u to %u blocks: %m",
+ errmsg("could not truncate relation %u/%u/%u/%u to %u blocks: %m",
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode,
+ forknum,
nblocks)));
if (!isTemp)
- register_dirty_segment(reln, v);
+ register_dirty_segment(reln, forknum, v);
v = v->mdfd_chain;
- Assert(ov != reln->md_fd); /* we never drop the 1st segment */
+ Assert(ov != reln->md_fd[forknum]); /* we never drop the 1st segment */
pfree(ov);
}
else if (priorblocks + ((BlockNumber) RELSEG_SIZE) > nblocks)
@@ -803,13 +846,14 @@ mdtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
if (FileTruncate(v->mdfd_vfd, (off_t) lastsegblocks * BLCKSZ) < 0)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not truncate relation %u/%u/%u to %u blocks: %m",
+ errmsg("could not truncate relation %u/%u/%u/%u to %u blocks: %m",
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode,
+ forknum,
nblocks)));
if (!isTemp)
- register_dirty_segment(reln, v);
+ register_dirty_segment(reln, forknum, v);
v = v->mdfd_chain;
ov->mdfd_chain = NULL;
}
@@ -832,7 +876,7 @@ mdtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
* nothing of dirty buffers that may exist inside the buffer manager.
*/
void
-mdimmedsync(SMgrRelation reln)
+mdimmedsync(SMgrRelation reln, ForkNumber forknum)
{
MdfdVec *v;
BlockNumber curnblk;
@@ -841,20 +885,21 @@ mdimmedsync(SMgrRelation reln)
* NOTE: mdnblocks makes sure we have opened all active segments, so that
* fsync loop will get them all!
*/
- curnblk = mdnblocks(reln);
+ curnblk = mdnblocks(reln, forknum);
- v = mdopen(reln, EXTENSION_FAIL);
+ v = mdopen(reln, forknum, EXTENSION_FAIL);
while (v != NULL)
{
if (FileSync(v->mdfd_vfd) < 0)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not fsync segment %u of relation %u/%u/%u: %m",
+ errmsg("could not fsync segment %u of relation %u/%u/%u/%u: %m",
v->mdfd_segno,
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
- reln->smgr_rnode.relNode)));
+ reln->smgr_rnode.relNode,
+ forknum)));
v = v->mdfd_chain;
}
}
@@ -1008,7 +1053,7 @@ mdsync(void)
* FileSync, since fd.c might have closed the file behind our
* back.
*/
- seg = _mdfd_getseg(reln,
+ seg = _mdfd_getseg(reln, entry->tag.forknum,
entry->tag.segno * ((BlockNumber) RELSEG_SIZE),
false, EXTENSION_RETURN_NULL);
if (seg != NULL &&
@@ -1024,19 +1069,21 @@ mdsync(void)
failures > 0)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not fsync segment %u of relation %u/%u/%u: %m",
+ errmsg("could not fsync segment %u of relation %u/%u/%u/%u: %m",
entry->tag.segno,
entry->tag.rnode.spcNode,
entry->tag.rnode.dbNode,
- entry->tag.rnode.relNode)));
+ entry->tag.rnode.relNode,
+ entry->tag.forknum)));
else
ereport(DEBUG1,
(errcode_for_file_access(),
- errmsg("could not fsync segment %u of relation %u/%u/%u, but retrying: %m",
+ errmsg("could not fsync segment %u of relation %u/%u/%u/%u but retrying: %m",
entry->tag.segno,
entry->tag.rnode.spcNode,
entry->tag.rnode.dbNode,
- entry->tag.rnode.relNode)));
+ entry->tag.rnode.relNode,
+ entry->tag.forknum)));
/*
* Absorb incoming requests and check to see if canceled.
@@ -1126,7 +1173,7 @@ mdpostckpt(void)
Assert((CycleCtr) (entry->cycle_ctr + 1) == mdckpt_cycle_ctr);
/* Unlink the file */
- path = relpath(entry->rnode);
+ path = relpath(entry->rnode, MAIN_FORKNUM);
if (unlink(path) < 0)
{
/*
@@ -1139,10 +1186,11 @@ mdpostckpt(void)
if (errno != ENOENT)
ereport(WARNING,
(errcode_for_file_access(),
- errmsg("could not remove relation %u/%u/%u: %m",
+ errmsg("could not remove relation %u/%u/%u/%u: %m",
entry->rnode.spcNode,
entry->rnode.dbNode,
- entry->rnode.relNode)));
+ entry->rnode.relNode,
+ MAIN_FORKNUM)));
}
pfree(path);
@@ -1161,26 +1209,27 @@ mdpostckpt(void)
* to be a performance problem).
*/
static void
-register_dirty_segment(SMgrRelation reln, MdfdVec *seg)
+register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
{
if (pendingOpsTable)
{
/* push it into local pending-ops table */
- RememberFsyncRequest(reln->smgr_rnode, seg->mdfd_segno);
+ RememberFsyncRequest(reln->smgr_rnode, forknum, seg->mdfd_segno);
}
else
{
- if (ForwardFsyncRequest(reln->smgr_rnode, seg->mdfd_segno))
+ if (ForwardFsyncRequest(reln->smgr_rnode, forknum, seg->mdfd_segno))
return; /* passed it off successfully */
if (FileSync(seg->mdfd_vfd) < 0)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not fsync segment %u of relation %u/%u/%u: %m",
+ errmsg("could not fsync segment %u of relation %u/%u/%u/%u: %m",
seg->mdfd_segno,
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
- reln->smgr_rnode.relNode)));
+ reln->smgr_rnode.relNode,
+ forknum)));
}
}
@@ -1196,7 +1245,7 @@ register_unlink(RelFileNode rnode)
if (pendingOpsTable)
{
/* push it into local pending-ops table */
- RememberFsyncRequest(rnode, UNLINK_RELATION_REQUEST);
+ RememberFsyncRequest(rnode, MAIN_FORKNUM, UNLINK_RELATION_REQUEST);
}
else
{
@@ -1208,7 +1257,8 @@ register_unlink(RelFileNode rnode)
* XXX should we just leave the file orphaned instead?
*/
Assert(IsUnderPostmaster);
- while (!ForwardFsyncRequest(rnode, UNLINK_RELATION_REQUEST))
+ while (!ForwardFsyncRequest(rnode, MAIN_FORKNUM,
+ UNLINK_RELATION_REQUEST))
pg_usleep(10000L); /* 10 msec seems a good number */
}
}
@@ -1233,7 +1283,7 @@ register_unlink(RelFileNode rnode)
* structure for them.)
*/
void
-RememberFsyncRequest(RelFileNode rnode, BlockNumber segno)
+RememberFsyncRequest(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
{
Assert(pendingOpsTable);
@@ -1246,7 +1296,8 @@ RememberFsyncRequest(RelFileNode rnode, BlockNumber segno)
hash_seq_init(&hstat, pendingOpsTable);
while ((entry = (PendingOperationEntry *) hash_seq_search(&hstat)) != NULL)
{
- if (RelFileNodeEquals(entry->tag.rnode, rnode))
+ if (RelFileNodeEquals(entry->tag.rnode, rnode) &&
+ entry->tag.forknum == forknum)
{
/* Okay, cancel this entry */
entry->canceled = true;
@@ -1313,6 +1364,7 @@ RememberFsyncRequest(RelFileNode rnode, BlockNumber segno)
/* ensure any pad bytes in the hash key are zeroed */
MemSet(&key, 0, sizeof(key));
key.rnode = rnode;
+ key.forknum = forknum;
key.segno = segno;
entry = (PendingOperationEntry *) hash_search(pendingOpsTable,
@@ -1346,12 +1398,12 @@ RememberFsyncRequest(RelFileNode rnode, BlockNumber segno)
* ForgetRelationFsyncRequests -- forget any fsyncs for a rel
*/
void
-ForgetRelationFsyncRequests(RelFileNode rnode)
+ForgetRelationFsyncRequests(RelFileNode rnode, ForkNumber forknum)
{
if (pendingOpsTable)
{
/* standalone backend or startup process: fsync state is local */
- RememberFsyncRequest(rnode, FORGET_RELATION_FSYNC);
+ RememberFsyncRequest(rnode, forknum, FORGET_RELATION_FSYNC);
}
else if (IsUnderPostmaster)
{
@@ -1365,7 +1417,7 @@ ForgetRelationFsyncRequests(RelFileNode rnode)
* which would be bad, so I'm inclined to assume that the bgwriter
* will always empty the queue soon.
*/
- while (!ForwardFsyncRequest(rnode, FORGET_RELATION_FSYNC))
+ while (!ForwardFsyncRequest(rnode, forknum, FORGET_RELATION_FSYNC))
pg_usleep(10000L); /* 10 msec seems a good number */
/*
@@ -1390,12 +1442,13 @@ ForgetDatabaseFsyncRequests(Oid dbid)
if (pendingOpsTable)
{
/* standalone backend or startup process: fsync state is local */
- RememberFsyncRequest(rnode, FORGET_DATABASE_FSYNC);
+ RememberFsyncRequest(rnode, InvalidForkNumber, FORGET_DATABASE_FSYNC);
}
else if (IsUnderPostmaster)
{
/* see notes in ForgetRelationFsyncRequests */
- while (!ForwardFsyncRequest(rnode, FORGET_DATABASE_FSYNC))
+ while (!ForwardFsyncRequest(rnode, InvalidForkNumber,
+ FORGET_DATABASE_FSYNC))
pg_usleep(10000L); /* 10 msec seems a good number */
}
}
@@ -1415,14 +1468,15 @@ _fdvec_alloc(void)
* and make a MdfdVec object for it. Returns NULL on failure.
*/
static MdfdVec *
-_mdfd_openseg(SMgrRelation reln, BlockNumber segno, int oflags)
+_mdfd_openseg(SMgrRelation reln, ForkNumber forknum, BlockNumber segno,
+ int oflags)
{
MdfdVec *v;
int fd;
char *path,
*fullpath;
- path = relpath(reln->smgr_rnode);
+ path = relpath(reln->smgr_rnode, forknum);
if (segno > 0)
{
@@ -1449,7 +1503,7 @@ _mdfd_openseg(SMgrRelation reln, BlockNumber segno, int oflags)
v->mdfd_vfd = fd;
v->mdfd_segno = segno;
v->mdfd_chain = NULL;
- Assert(_mdnblocks(reln, v) <= ((BlockNumber) RELSEG_SIZE));
+ Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
/* all done */
return v;
@@ -1464,10 +1518,10 @@ _mdfd_openseg(SMgrRelation reln, BlockNumber segno, int oflags)
* in the EXTENSION_CREATE case.
*/
static MdfdVec *
-_mdfd_getseg(SMgrRelation reln, BlockNumber blkno, bool isTemp,
- ExtensionBehavior behavior)
+_mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno,
+ bool isTemp, ExtensionBehavior behavior)
{
- MdfdVec *v = mdopen(reln, behavior);
+ MdfdVec *v = mdopen(reln, forknum, behavior);
BlockNumber targetseg;
BlockNumber nextsegno;
@@ -1497,20 +1551,21 @@ _mdfd_getseg(SMgrRelation reln, BlockNumber blkno, bool isTemp,
*/
if (behavior == EXTENSION_CREATE || InRecovery)
{
- if (_mdnblocks(reln, v) < RELSEG_SIZE)
+ if (_mdnblocks(reln, forknum, v) < RELSEG_SIZE)
{
char *zerobuf = palloc0(BLCKSZ);
- mdextend(reln, nextsegno * ((BlockNumber) RELSEG_SIZE) - 1,
+ mdextend(reln, forknum,
+ nextsegno * ((BlockNumber) RELSEG_SIZE) - 1,
zerobuf, isTemp);
pfree(zerobuf);
}
- v->mdfd_chain = _mdfd_openseg(reln, nextsegno, O_CREAT);
+ v->mdfd_chain = _mdfd_openseg(reln, forknum, +nextsegno, O_CREAT);
}
else
{
/* We won't create segment if not existent */
- v->mdfd_chain = _mdfd_openseg(reln, nextsegno, 0);
+ v->mdfd_chain = _mdfd_openseg(reln, forknum, nextsegno, 0);
}
if (v->mdfd_chain == NULL)
{
@@ -1519,11 +1574,12 @@ _mdfd_getseg(SMgrRelation reln, BlockNumber blkno, bool isTemp,
return NULL;
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not open segment %u of relation %u/%u/%u (target block %u): %m",
+ errmsg("could not open segment %u of relation %u/%u/%u/%u (target block %u): %m",
nextsegno,
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode,
+ forknum,
blkno)));
}
}
@@ -1536,7 +1592,7 @@ _mdfd_getseg(SMgrRelation reln, BlockNumber blkno, bool isTemp,
* Get number of blocks present in a single disk file
*/
static BlockNumber
-_mdnblocks(SMgrRelation reln, MdfdVec *seg)
+_mdnblocks(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
{
off_t len;
@@ -1544,11 +1600,12 @@ _mdnblocks(SMgrRelation reln, MdfdVec *seg)
if (len < 0)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not seek to end of segment %u of relation %u/%u/%u: %m",
+ errmsg("could not seek to end of segment %u of relation %u/%u/%u/%u: %m",
seg->mdfd_segno,
reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
- reln->smgr_rnode.relNode)));
+ reln->smgr_rnode.relNode,
+ forknum)));
/* note that this calculation will ignore any partial block at EOF */
return (BlockNumber) (len / BLCKSZ);
}
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index d0282f8a6d7..da4a9766ca9 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.110 2008/06/12 09:12:31 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.111 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,19 +42,22 @@ typedef struct f_smgr
{
void (*smgr_init) (void); /* may be NULL */
void (*smgr_shutdown) (void); /* may be NULL */
- void (*smgr_close) (SMgrRelation reln);
- void (*smgr_create) (SMgrRelation reln, bool isRedo);
- void (*smgr_unlink) (RelFileNode rnode, bool isRedo);
- void (*smgr_extend) (SMgrRelation reln, BlockNumber blocknum,
- char *buffer, bool isTemp);
- void (*smgr_read) (SMgrRelation reln, BlockNumber blocknum,
- char *buffer);
- void (*smgr_write) (SMgrRelation reln, BlockNumber blocknum,
- char *buffer, bool isTemp);
- BlockNumber (*smgr_nblocks) (SMgrRelation reln);
- void (*smgr_truncate) (SMgrRelation reln, BlockNumber nblocks,
- bool isTemp);
- void (*smgr_immedsync) (SMgrRelation reln);
+ void (*smgr_close) (SMgrRelation reln, ForkNumber forknum);
+ void (*smgr_create) (SMgrRelation reln, ForkNumber forknum,
+ bool isRedo);
+ bool (*smgr_exists) (SMgrRelation reln, ForkNumber forknum);
+ void (*smgr_unlink) (RelFileNode rnode, ForkNumber forknum,
+ bool isRedo);
+ void (*smgr_extend) (SMgrRelation reln, ForkNumber forknum,
+ BlockNumber blocknum, char *buffer, bool isTemp);
+ void (*smgr_read) (SMgrRelation reln, ForkNumber forknum,
+ BlockNumber blocknum, char *buffer);
+ void (*smgr_write) (SMgrRelation reln, ForkNumber forknum,
+ BlockNumber blocknum, char *buffer, bool isTemp);
+ BlockNumber (*smgr_nblocks) (SMgrRelation reln, ForkNumber forknum);
+ 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 */
@@ -65,7 +68,7 @@ typedef struct f_smgr
static const f_smgr smgrsw[] = {
/* magnetic disk */
- {mdinit, NULL, mdclose, mdcreate, mdunlink, mdextend,
+ {mdinit, NULL, mdclose, mdcreate, mdexists, mdunlink, mdextend,
mdread, mdwrite, mdnblocks, mdtruncate, mdimmedsync,
NULL, NULL, mdpreckpt, mdsync, mdpostckpt
}
@@ -102,6 +105,7 @@ static HTAB *SMgrRelationHash = NULL;
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 */
@@ -126,19 +130,21 @@ static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
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, int which,
- bool isTemp, bool isRedo);
+static void smgr_internal_unlink(RelFileNode rnode, ForkNumber forknum,
+ int which, bool isTemp, bool isRedo);
/*
@@ -211,10 +217,15 @@ smgropen(RelFileNode rnode)
/* Initialize it if not present before */
if (!found)
{
+ int forknum;
+
/* hash_search already filled in the lookup key */
reln->smgr_owner = NULL;
reln->smgr_which = 0; /* we only have md.c at present */
- reln->md_fd = NULL; /* mark it not open */
+
+ /* mark it not open */
+ for(forknum = 0; forknum <= MAX_FORKNUM; forknum++)
+ reln->md_fd[forknum] = NULL;
}
return reln;
@@ -244,14 +255,25 @@ smgrsetowner(SMgrRelation *owner, SMgrRelation reln)
}
/*
+ * smgrexists() -- Does the underlying file for a fork exist?
+ */
+bool
+smgrexists(SMgrRelation reln, ForkNumber forknum)
+{
+ return (*(smgrsw[reln->smgr_which].smgr_exists)) (reln, forknum);
+}
+
+/*
* smgrclose() -- Close and delete an SMgrRelation object.
*/
void
smgrclose(SMgrRelation reln)
{
SMgrRelation *owner;
+ ForkNumber forknum;
- (*(smgrsw[reln->smgr_which].smgr_close)) (reln);
+ for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
+ (*(smgrsw[reln->smgr_which].smgr_close)) (reln, forknum);
owner = reln->smgr_owner;
@@ -315,7 +337,8 @@ smgrclosenode(RelFileNode rnode)
* smgrcreate() -- Create a new relation.
*
* Given an already-created (but presumably unused) SMgrRelation,
- * cause the underlying disk file or other storage to be created.
+ * cause the underlying disk file or other storage for the fork
+ * 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
@@ -323,7 +346,7 @@ smgrclosenode(RelFileNode rnode)
* tell whether to drop the file.
*/
void
-smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
+smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isTemp, bool isRedo)
{
XLogRecPtr lsn;
XLogRecData rdata;
@@ -334,7 +357,7 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
* Exit quickly in WAL replay mode if we've already opened the file.
* If it's open, it surely must exist.
*/
- if (isRedo && reln->md_fd != NULL)
+ if (isRedo && reln->md_fd[forknum] != NULL)
return;
/*
@@ -350,7 +373,7 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
reln->smgr_rnode.dbNode,
isRedo);
- (*(smgrsw[reln->smgr_which].smgr_create)) (reln, isRedo);
+ (*(smgrsw[reln->smgr_which].smgr_create)) (reln, forknum, isRedo);
if (isRedo)
return;
@@ -360,6 +383,7 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
* will be dropped at abort time.
*/
xlrec.rnode = reln->smgr_rnode;
+ xlrec.forknum = forknum;
rdata.data = (char *) &xlrec;
rdata.len = sizeof(xlrec);
@@ -372,6 +396,7 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
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 */
@@ -383,13 +408,11 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
/*
* smgrscheduleunlink() -- Schedule unlinking a relation at xact commit.
*
- * The relation is marked to be removed from the store if we
- * successfully commit the current transaction.
- *
- * This also implies smgrclose() on the SMgrRelation object.
+ * The fork is marked to be removed from the store if we successfully
+ * commit the current transaction.
*/
void
-smgrscheduleunlink(SMgrRelation reln, bool isTemp)
+smgrscheduleunlink(SMgrRelation reln, ForkNumber forknum, bool isTemp)
{
PendingRelDelete *pending;
@@ -397,6 +420,7 @@ smgrscheduleunlink(SMgrRelation reln, bool isTemp)
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 */
@@ -413,51 +437,49 @@ smgrscheduleunlink(SMgrRelation reln, bool isTemp)
* the existing list entry and delete the physical file immediately, but
* for now I'll keep the logic simple.
*/
-
- /* Now close the file and throw away the hashtable entry */
- smgrclose(reln);
}
/*
* smgrdounlink() -- Immediately unlink a relation.
*
- * The relation is removed from the store. This should not be used
- * during transactional operations, since it can't be undone.
+ * The specified fork of the relation is removed from the store. This
+ * should not be used during transactional operations, since it can't be
+ * undone.
*
* If isRedo is true, it is okay for the underlying file to be gone
* already.
- *
- * This also implies smgrclose() on the SMgrRelation object.
*/
void
-smgrdounlink(SMgrRelation reln, bool isTemp, bool isRedo)
+smgrdounlink(SMgrRelation reln, ForkNumber forknum, bool isTemp, bool isRedo)
{
RelFileNode rnode = reln->smgr_rnode;
int which = reln->smgr_which;
- /* Close the file and throw away the hashtable entry */
- smgrclose(reln);
+ /* Close the fork */
+ (*(smgrsw[which].smgr_close)) (reln, forknum);
- smgr_internal_unlink(rnode, which, isTemp, isRedo);
+ smgr_internal_unlink(rnode, forknum, which, isTemp, isRedo);
}
/*
* Shared subroutine that actually does the unlink ...
*/
static void
-smgr_internal_unlink(RelFileNode rnode, int which, bool isTemp, bool isRedo)
+smgr_internal_unlink(RelFileNode rnode, ForkNumber forknum,
+ int which, bool isTemp, bool isRedo)
{
/*
* Get rid of any remaining buffers for the relation. bufmgr will just
* drop them without bothering to write the contents.
*/
- DropRelFileNodeBuffers(rnode, isTemp, 0);
+ DropRelFileNodeBuffers(rnode, forknum, isTemp, 0);
/*
* Tell the free space map to forget this relation. It won't be accessed
* any more anyway, but we may as well recycle the map space quickly.
*/
- FreeSpaceMapForgetRel(&rnode);
+ if (forknum == MAIN_FORKNUM)
+ FreeSpaceMapForgetRel(&rnode);
/*
* It'd be nice to tell the stats collector to forget it immediately, too.
@@ -473,7 +495,7 @@ smgr_internal_unlink(RelFileNode rnode, int which, bool isTemp, bool isRedo)
* ERROR, because we've already decided to commit or abort the current
* xact.
*/
- (*(smgrsw[which].smgr_unlink)) (rnode, isRedo);
+ (*(smgrsw[which].smgr_unlink)) (rnode, forknum, isRedo);
}
/*
@@ -486,9 +508,11 @@ smgr_internal_unlink(RelFileNode rnode, int which, bool isTemp, bool isRedo)
* causes intervening file space to become filled with zeroes.
*/
void
-smgrextend(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
+smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+ char *buffer, bool isTemp)
{
- (*(smgrsw[reln->smgr_which].smgr_extend)) (reln, blocknum, buffer, isTemp);
+ (*(smgrsw[reln->smgr_which].smgr_extend)) (reln, forknum, blocknum,
+ buffer, isTemp);
}
/*
@@ -500,9 +524,10 @@ smgrextend(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
* return pages in the format that POSTGRES expects.
*/
void
-smgrread(SMgrRelation reln, BlockNumber blocknum, char *buffer)
+smgrread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+ char *buffer)
{
- (*(smgrsw[reln->smgr_which].smgr_read)) (reln, blocknum, buffer);
+ (*(smgrsw[reln->smgr_which].smgr_read)) (reln, forknum, blocknum, buffer);
}
/*
@@ -521,9 +546,11 @@ smgrread(SMgrRelation reln, BlockNumber blocknum, char *buffer)
* made to fsync the write before checkpointing.
*/
void
-smgrwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
+smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+ char *buffer, bool isTemp)
{
- (*(smgrsw[reln->smgr_which].smgr_write)) (reln, blocknum, buffer, isTemp);
+ (*(smgrsw[reln->smgr_which].smgr_write)) (reln, forknum, blocknum,
+ buffer, isTemp);
}
/*
@@ -531,9 +558,9 @@ smgrwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
* supplied relation.
*/
BlockNumber
-smgrnblocks(SMgrRelation reln)
+smgrnblocks(SMgrRelation reln, ForkNumber forknum)
{
- return (*(smgrsw[reln->smgr_which].smgr_nblocks)) (reln);
+ return (*(smgrsw[reln->smgr_which].smgr_nblocks)) (reln, forknum);
}
/*
@@ -541,13 +568,14 @@ smgrnblocks(SMgrRelation reln)
* of blocks
*/
void
-smgrtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
+smgrtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks,
+ bool isTemp)
{
/*
* Get rid of any buffers for the about-to-be-deleted blocks. bufmgr will
* just drop them without bothering to write the contents.
*/
- DropRelFileNodeBuffers(reln->smgr_rnode, isTemp, nblocks);
+ DropRelFileNodeBuffers(reln->smgr_rnode, forknum, isTemp, nblocks);
/*
* Tell the free space map to forget anything it may have stored for the
@@ -557,7 +585,8 @@ smgrtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
FreeSpaceMapTruncateRel(&reln->smgr_rnode, nblocks);
/* Do the truncation */
- (*(smgrsw[reln->smgr_which].smgr_truncate)) (reln, nblocks, isTemp);
+ (*(smgrsw[reln->smgr_which].smgr_truncate)) (reln, forknum, nblocks,
+ isTemp);
if (!isTemp)
{
@@ -570,6 +599,7 @@ smgrtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
xlrec.blkno = nblocks;
xlrec.rnode = reln->smgr_rnode;
+ xlrec.forknum = forknum;
rdata.data = (char *) &xlrec;
rdata.len = sizeof(xlrec);
@@ -604,9 +634,9 @@ smgrtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
* otherwise the sync is not very meaningful.
*/
void
-smgrimmedsync(SMgrRelation reln)
+smgrimmedsync(SMgrRelation reln, ForkNumber forknum)
{
- (*(smgrsw[reln->smgr_which].smgr_immedsync)) (reln);
+ (*(smgrsw[reln->smgr_which].smgr_immedsync)) (reln, forknum);
}
@@ -666,6 +696,7 @@ smgrDoPendingDeletes(bool isCommit)
/* do deletion if called for */
if (pending->atCommit == isCommit)
smgr_internal_unlink(pending->relnode,
+ pending->forknum,
pending->which,
pending->isTemp,
false);
@@ -680,7 +711,7 @@ smgrDoPendingDeletes(bool isCommit)
* 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.
+ * *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
@@ -690,11 +721,11 @@ smgrDoPendingDeletes(bool isCommit)
* by upper-level transactions.
*/
int
-smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr, bool *haveNonTemp)
+smgrGetPendingDeletes(bool forCommit, RelFileFork **ptr, bool *haveNonTemp)
{
int nestLevel = GetCurrentTransactionNestLevel();
int nrels;
- RelFileNode *rptr;
+ RelFileFork *rptr;
PendingRelDelete *pending;
nrels = 0;
@@ -710,12 +741,16 @@ smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr, bool *haveNonTemp)
*ptr = NULL;
return 0;
}
- rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
+ rptr = (RelFileFork *) palloc(nrels * sizeof(RelFileFork));
*ptr = rptr;
for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{
if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit)
- *rptr++ = pending->relnode;
+ {
+ rptr->rnode = pending->relnode;
+ rptr->forknum = pending->forknum;
+ rptr++;
+ }
if (haveNonTemp && !pending->isTemp)
*haveNonTemp = true;
}
@@ -843,7 +878,7 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
SMgrRelation reln;
reln = smgropen(xlrec->rnode);
- smgrcreate(reln, false, true);
+ smgrcreate(reln, xlrec->forknum, false, true);
}
else if (info == XLOG_SMGR_TRUNCATE)
{
@@ -858,7 +893,7 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
* XLogOpenRelation, we prefer to recreate the rel and replay the log
* as best we can until the drop is seen.
*/
- smgrcreate(reln, false, true);
+ smgrcreate(reln, xlrec->forknum, false, true);
/* Can't use smgrtruncate because it would try to xlog */
@@ -867,7 +902,8 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
* truncated blocks. We must do this, else subsequent XLogReadBuffer
* operations will not re-extend the file properly.
*/
- DropRelFileNodeBuffers(xlrec->rnode, false, xlrec->blkno);
+ DropRelFileNodeBuffers(xlrec->rnode, xlrec->forknum, false,
+ xlrec->blkno);
/*
* Tell the free space map to forget anything it may have stored for
@@ -878,11 +914,12 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
/* 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->blkno);
+ XLogTruncateRelation(xlrec->rnode, xlrec->forknum, xlrec->blkno);
}
else
elog(PANIC, "smgr_redo: unknown op code %u", info);
@@ -897,17 +934,18 @@ smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
{
xl_smgr_create *xlrec = (xl_smgr_create *) rec;
- appendStringInfo(buf, "file create: %u/%u/%u",
+ appendStringInfo(buf, "file create: %u/%u/%u/%u",
xlrec->rnode.spcNode, xlrec->rnode.dbNode,
- xlrec->rnode.relNode);
+ xlrec->rnode.relNode, xlrec->forknum);
}
else if (info == XLOG_SMGR_TRUNCATE)
{
xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
- appendStringInfo(buf, "file truncate: %u/%u/%u to %u blocks",
+ appendStringInfo(buf, "file truncate: %u/%u/%u/%u to %u blocks",
xlrec->rnode.spcNode, xlrec->rnode.dbNode,
- xlrec->rnode.relNode, xlrec->blkno);
+ xlrec->rnode.relNode, xlrec->forknum,
+ xlrec->blkno);
}
else
appendStringInfo(buf, "UNKNOWN");
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
index c358cdea7b4..e85d11c3834 100644
--- a/src/backend/utils/adt/dbsize.c
+++ b/src/backend/utils/adt/dbsize.c
@@ -5,7 +5,7 @@
* Copyright (c) 2002-2008, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/dbsize.c,v 1.19 2008/06/19 00:46:05 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/dbsize.c,v 1.20 2008/08/11 11:05:11 heikki Exp $
*
*/
@@ -255,7 +255,8 @@ calculate_relation_size(RelFileNode *rfn)
char pathname[MAXPGPATH];
unsigned int segcount = 0;
- relationpath = relpath(*rfn);
+ /* XXX: This ignores the other forks. */
+ relationpath = relpath(*rfn, MAIN_FORKNUM);
for (segcount = 0;; segcount++)
{
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index c6b7d5dc114..d6f9473c5ee 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.137 2008/06/19 00:46:06 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.138 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -127,7 +127,8 @@ extern XLogRecPtr log_heap_clean(Relation reln, Buffer buffer,
extern XLogRecPtr log_heap_freeze(Relation reln, Buffer buffer,
TransactionId cutoff_xid,
OffsetNumber *offsets, int offcnt);
-extern XLogRecPtr log_newpage(RelFileNode *rnode, BlockNumber blk, Page page);
+extern XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum,
+ BlockNumber blk, Page page);
/* in heap/pruneheap.c */
extern void heap_page_prune_opt(Relation relation, Buffer buffer,
diff --git a/src/include/access/htup.h b/src/include/access/htup.h
index 8bfdf26697e..85271c26c3a 100644
--- a/src/include/access/htup.h
+++ b/src/include/access/htup.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/htup.h,v 1.100 2008/07/13 20:45:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/htup.h,v 1.101 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -670,6 +670,7 @@ typedef struct xl_heap_clean
typedef struct xl_heap_newpage
{
RelFileNode node;
+ ForkNumber forknum;
BlockNumber blkno; /* location of new page */
/* entire page contents follow at end of record */
} xl_heap_newpage;
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index dff05c73db5..c887716e591 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.94 2008/03/04 19:54:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.95 2008/08/11 11:05:11 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 RelFileNodes */
+ int nrels; /* number of RelFileForks */
int nsubxacts; /* number of subtransaction XIDs */
- /* Array of RelFileNode(s) to drop at commit */
- RelFileNode xnodes[1]; /* VARIABLE LENGTH ARRAY */
+ /* Array of RelFileFork(s) to drop at commit */
+ RelFileFork 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 RelFileNodes */
+ int nrels; /* number of RelFileForks */
int nsubxacts; /* number of subtransaction XIDs */
- /* Array of RelFileNode(s) to drop at abort */
- RelFileNode xnodes[1]; /* VARIABLE LENGTH ARRAY */
+ /* Array of RelFileFork(s) to drop at abort */
+ RelFileFork xnodes[1]; /* VARIABLE LENGTH ARRAY */
/* ARRAY OF ABORTED SUBTRANSACTION XIDs FOLLOWS */
} xl_xact_abort;
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 88fe0b6a95f..c5f1a0f502f 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -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/include/access/xlog_internal.h,v 1.23 2008/02/17 02:09:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/xlog_internal.h,v 1.24 2008/08/11 11:05:11 heikki Exp $
*/
#ifndef XLOG_INTERNAL_H
#define XLOG_INTERNAL_H
@@ -40,6 +40,7 @@
typedef struct BkpBlock
{
RelFileNode node; /* relation containing block */
+ ForkNumber fork; /* fork within the relation */
BlockNumber block; /* block number */
uint16 hole_offset; /* number of bytes before "hole" */
uint16 hole_length; /* number of bytes in "hole" */
diff --git a/src/include/access/xlogutils.h b/src/include/access/xlogutils.h
index f1585c032a5..0c81d42e44d 100644
--- a/src/include/access/xlogutils.h
+++ b/src/include/access/xlogutils.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/xlogutils.h,v 1.25 2008/06/19 00:46:06 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/access/xlogutils.h,v 1.26 2008/08/11 11:05:11 heikki Exp $
*/
#ifndef XLOG_UTILS_H
#define XLOG_UTILS_H
@@ -19,11 +19,14 @@
extern void XLogCheckInvalidPages(void);
-extern void XLogDropRelation(RelFileNode rnode);
+extern void XLogDropRelation(RelFileNode rnode, ForkNumber forknum);
extern void XLogDropDatabase(Oid dbid);
-extern void XLogTruncateRelation(RelFileNode rnode, BlockNumber nblocks);
+extern void XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum,
+ BlockNumber nblocks);
extern Buffer XLogReadBuffer(RelFileNode rnode, BlockNumber blkno, bool init);
+extern Buffer XLogReadBufferWithFork(RelFileNode rnode, ForkNumber forknum,
+ BlockNumber blkno, bool init);
extern Relation CreateFakeRelcacheEntry(RelFileNode rnode);
extern void FreeFakeRelcacheEntry(Relation fakerel);
diff --git a/src/include/catalog/catalog.h b/src/include/catalog/catalog.h
index 845ef035bd5..52a69e13419 100644
--- a/src/include/catalog/catalog.h
+++ b/src/include/catalog/catalog.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/catalog/catalog.h,v 1.40 2008/06/19 00:46:06 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.41 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,7 +19,7 @@
#include "utils/relcache.h"
-extern char *relpath(RelFileNode rnode);
+extern char *relpath(RelFileNode rnode, ForkNumber forknum);
extern char *GetDatabasePath(Oid dbNode, Oid spcNode);
extern bool IsSystemRelation(Relation relation);
diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h
index b1c6fd59fcb..3dc02bc400d 100644
--- a/src/include/postmaster/bgwriter.h
+++ b/src/include/postmaster/bgwriter.h
@@ -5,7 +5,7 @@
*
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/include/postmaster/bgwriter.h,v 1.11 2008/01/01 19:45:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/postmaster/bgwriter.h,v 1.12 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,7 +27,8 @@ extern void BackgroundWriterMain(void);
extern void RequestCheckpoint(int flags);
extern void CheckpointWriteDelay(int flags, double progress);
-extern bool ForwardFsyncRequest(RelFileNode rnode, BlockNumber segno);
+extern bool ForwardFsyncRequest(RelFileNode rnode, ForkNumber forknum,
+ BlockNumber segno);
extern void AbsorbFsyncRequests(void);
extern Size BgWriterShmemSize(void);
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index 589baa0a7e5..a8861d29a8e 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/buf_internals.h,v 1.97 2008/06/19 00:46:06 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/storage/buf_internals.h,v 1.98 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -65,6 +65,7 @@ typedef bits16 BufFlags;
typedef struct buftag
{
RelFileNode rnode; /* physical relation identifier */
+ ForkNumber forkNum;
BlockNumber blockNum; /* blknum relative to begin of reln */
} BufferTag;
@@ -73,19 +74,22 @@ typedef struct buftag
(a).rnode.spcNode = InvalidOid, \
(a).rnode.dbNode = InvalidOid, \
(a).rnode.relNode = InvalidOid, \
+ (a).forkNum = InvalidForkNumber, \
(a).blockNum = InvalidBlockNumber \
)
-#define INIT_BUFFERTAG(a,xx_rnode,xx_blockNum) \
+#define INIT_BUFFERTAG(a,xx_rnode,xx_forkNum,xx_blockNum) \
( \
(a).rnode = (xx_rnode), \
+ (a).forkNum = (xx_forkNum), \
(a).blockNum = (xx_blockNum) \
)
#define BUFFERTAGS_EQUAL(a,b) \
( \
RelFileNodeEquals((a).rnode, (b).rnode) && \
- (a).blockNum == (b).blockNum \
+ (a).blockNum == (b).blockNum && \
+ (a).forkNum == (b).forkNum \
)
/*
@@ -202,10 +206,10 @@ extern int BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id);
extern void BufTableDelete(BufferTag *tagPtr, uint32 hashcode);
/* localbuf.c */
-extern BufferDesc *LocalBufferAlloc(SMgrRelation reln, BlockNumber blockNum,
- bool *foundPtr);
+extern BufferDesc *LocalBufferAlloc(SMgrRelation reln, ForkNumber forkNum,
+ BlockNumber blockNum, bool *foundPtr);
extern void MarkLocalBufferDirty(Buffer buffer);
-extern void DropRelFileNodeLocalBuffers(RelFileNode rnode,
+extern void DropRelFileNodeLocalBuffers(RelFileNode rnode, ForkNumber forkNum,
BlockNumber firstDelBlock);
extern void AtEOXact_LocalBuffers(bool isCommit);
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index f940ae466d5..72d4aec3979 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.114 2008/06/19 00:46:06 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.115 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -144,11 +144,13 @@ extern PGDLLIMPORT int32 *LocalRefCount;
* prototypes for functions in bufmgr.c
*/
extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
+extern Buffer ReadBufferWithFork(Relation reln, ForkNumber forkNum, BlockNumber blockNum);
extern Buffer ReadBufferWithStrategy(Relation reln, BlockNumber blockNum,
BufferAccessStrategy strategy);
-extern Buffer ReadOrZeroBuffer(Relation reln, BlockNumber blockNum);
+extern Buffer ReadOrZeroBuffer(Relation reln, ForkNumber forkNum,
+ BlockNumber blockNum);
extern Buffer ReadBufferWithoutRelcache(RelFileNode rnode, bool isTemp,
- BlockNumber blockNum, bool zeroPage);
+ ForkNumber forkNum, BlockNumber blockNum, bool zeroPage);
extern void ReleaseBuffer(Buffer buffer);
extern void UnlockReleaseBuffer(Buffer buffer);
extern void MarkBufferDirty(Buffer buffer);
@@ -169,15 +171,16 @@ 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, bool istemp,
- BlockNumber firstDelBlock);
+extern void DropRelFileNodeBuffers(RelFileNode rnode, ForkNumber forkNum,
+ bool istemp, BlockNumber firstDelBlock);
extern void DropDatabaseBuffers(Oid dbid);
#ifdef NOT_USED
extern void PrintPinnedBufs(void);
#endif
extern Size BufferShmemSize(void);
-extern RelFileNode BufferGetFileNode(Buffer buffer);
+extern void BufferGetTag(Buffer buffer, RelFileNode *rnode,
+ ForkNumber *forknum, BlockNumber *blknum);
extern void SetBufferCommitInfoNeedsSave(Buffer buffer);
diff --git a/src/include/storage/relfilenode.h b/src/include/storage/relfilenode.h
index 9638294b4a4..8ac8147ed93 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.15 2008/01/01 19:45:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/relfilenode.h,v 1.16 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -15,8 +15,25 @@
#define RELFILENODE_H
/*
+ * The physical storage of a relation consists of one or more forks. The
+ * main fork is always created, but in addition to that there can be
+ * additional forks for storing various metadata. ForkNumber is used when
+ * we need to refer to a specific fork in a relation.
+ */
+typedef enum ForkNumber
+{
+ InvalidForkNumber = -1,
+ MAIN_FORKNUM = 0
+ /* NOTE: change NUM_FORKS below when you add new forks */
+} ForkNumber;
+
+#define MAX_FORKNUM MAIN_FORKNUM
+
+/*
* RelFileNode must provide all that we need to know to physically access
- * a relation.
+ * a relation. Note, however, that a "physical" relation is comprised of
+ * multiple files on the filesystem, as each fork is stored as a separate
+ * file, and each fork can be divided into multiple segments. See md.c.
*
* spcNode identifies the tablespace of the relation. It corresponds to
* pg_tablespace.oid.
@@ -57,4 +74,13 @@ 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 9e9c6c023b9..d4999c1049a 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.62 2008/01/01 19:45:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/smgr.h,v 1.63 2008/08/11 11:05:11 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -51,7 +51,8 @@ typedef struct SMgrRelationData
*/
int smgr_which; /* storage manager selector */
- struct _MdfdVec *md_fd; /* for md.c; NULL if not open */
+ /* for md.c; NULL for forks that are not open */
+ struct _MdfdVec *md_fd[MAX_FORKNUM + 1];
} SMgrRelationData;
typedef SMgrRelationData *SMgrRelation;
@@ -59,24 +60,29 @@ typedef SMgrRelationData *SMgrRelation;
extern void smgrinit(void);
extern SMgrRelation smgropen(RelFileNode rnode);
+extern bool smgrexists(SMgrRelation reln, ForkNumber forknum);
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, bool isTemp, bool isRedo);
-extern void smgrscheduleunlink(SMgrRelation reln, bool isTemp);
-extern void smgrdounlink(SMgrRelation reln, bool isTemp, bool isRedo);
-extern void smgrextend(SMgrRelation reln, BlockNumber blocknum, char *buffer,
- bool isTemp);
-extern void smgrread(SMgrRelation reln, BlockNumber blocknum, char *buffer);
-extern void smgrwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer,
- bool isTemp);
-extern BlockNumber smgrnblocks(SMgrRelation reln);
-extern void smgrtruncate(SMgrRelation reln, BlockNumber nblocks,
- bool isTemp);
-extern void smgrimmedsync(SMgrRelation reln);
+extern void smgrcreate(SMgrRelation reln, ForkNumber forknum,
+ bool isTemp, bool isRedo);
+extern void smgrscheduleunlink(SMgrRelation reln, ForkNumber forknum,
+ bool isTemp);
+extern void smgrdounlink(SMgrRelation reln, ForkNumber forknum,
+ bool isTemp, bool isRedo);
+extern void smgrextend(SMgrRelation reln, ForkNumber forknum,
+ BlockNumber blocknum, char *buffer, bool isTemp);
+extern void smgrread(SMgrRelation reln, ForkNumber forknum,
+ BlockNumber blocknum, char *buffer);
+extern void smgrwrite(SMgrRelation reln, ForkNumber forknum,
+ BlockNumber blocknum, char *buffer, bool isTemp);
+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, RelFileNode **ptr,
+extern int smgrGetPendingDeletes(bool forCommit, RelFileFork **ptr,
bool *haveNonTemp);
extern void AtSubCommit_smgr(void);
extern void AtSubAbort_smgr(void);
@@ -95,23 +101,27 @@ extern void smgr_desc(StringInfo buf, uint8 xl_info, char *rec);
/* in md.c */
extern void mdinit(void);
-extern void mdclose(SMgrRelation reln);
-extern void mdcreate(SMgrRelation reln, bool isRedo);
-extern void mdunlink(RelFileNode rnode, bool isRedo);
-extern void mdextend(SMgrRelation reln, BlockNumber blocknum, char *buffer,
- bool isTemp);
-extern void mdread(SMgrRelation reln, BlockNumber blocknum, char *buffer);
-extern void mdwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer,
- bool isTemp);
-extern BlockNumber mdnblocks(SMgrRelation reln);
-extern void mdtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp);
-extern void mdimmedsync(SMgrRelation reln);
+extern void mdclose(SMgrRelation reln, ForkNumber forknum);
+extern void mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo);
+extern bool mdexists(SMgrRelation reln, ForkNumber forknum);
+extern void mdunlink(RelFileNode rnode, ForkNumber forknum, bool isRedo);
+extern void mdextend(SMgrRelation reln, ForkNumber forknum,
+ BlockNumber blocknum, char *buffer, bool isTemp);
+extern void mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+ char *buffer);
+extern void mdwrite(SMgrRelation reln, ForkNumber forknum,
+ BlockNumber blocknum, char *buffer, bool isTemp);
+extern BlockNumber mdnblocks(SMgrRelation reln, ForkNumber forknum);
+extern void mdtruncate(SMgrRelation reln, ForkNumber forknum,
+ BlockNumber nblocks, bool isTemp);
+extern void mdimmedsync(SMgrRelation reln, ForkNumber forknum);
extern void mdpreckpt(void);
extern void mdsync(void);
extern void mdpostckpt(void);
-extern void RememberFsyncRequest(RelFileNode rnode, BlockNumber segno);
-extern void ForgetRelationFsyncRequests(RelFileNode rnode);
+extern void RememberFsyncRequest(RelFileNode rnode, ForkNumber forknum,
+ BlockNumber segno);
+extern void ForgetRelationFsyncRequests(RelFileNode rnode, ForkNumber forknum);
extern void ForgetDatabaseFsyncRequests(Oid dbid);
/* smgrtype.c */