Commit 5df307c7 authored by Tom Lane's avatar Tom Lane

Restructure local-buffer handling per recent pghackers discussion.

The local buffer manager is no longer used for newly-created relations
(unless they are TEMP); a new non-TEMP relation goes through the shared
bufmgr and thus will participate normally in checkpoints.  But TEMP relations
use the local buffer manager throughout their lifespan.  Also, operations
in TEMP relations are not logged in WAL, thus improving performance.
Since it's no longer necessary to fsync relations as they move out of the
local buffers into shared buffers, quite a lot of smgr.c/md.c/fd.c code
is no longer needed and has been removed: there's no concept of a dirty
relation anymore in md.c/fd.c, and we never fsync anything but WAL.
Still TODO: improve local buffer management algorithms so that it would
be reasonable to increase NLocBuffer.
parent 35cd432b
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.143 2002/07/30 16:08:33 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.144 2002/08/06 02:36:33 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -1155,6 +1155,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid) ...@@ -1155,6 +1155,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid)
pgstat_count_heap_insert(&relation->pgstat_info); pgstat_count_heap_insert(&relation->pgstat_info);
/* XLOG stuff */ /* XLOG stuff */
if (!relation->rd_istemp)
{ {
xl_heap_insert xlrec; xl_heap_insert xlrec;
xl_heap_header xlhdr; xl_heap_header xlhdr;
...@@ -1204,6 +1205,12 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid) ...@@ -1204,6 +1205,12 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid)
PageSetLSN(page, recptr); PageSetLSN(page, recptr);
PageSetSUI(page, ThisStartUpID); PageSetSUI(page, ThisStartUpID);
} }
else
{
/* No XLOG record, but still need to flag that XID exists on disk */
MyXactMadeTempRelUpdate = true;
}
END_CRIT_SECTION(); END_CRIT_SECTION();
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
...@@ -1323,12 +1330,15 @@ l1: ...@@ -1323,12 +1330,15 @@ l1:
} }
START_CRIT_SECTION(); START_CRIT_SECTION();
/* store transaction information of xact deleting the tuple */ /* store transaction information of xact deleting the tuple */
tp.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED | tp.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE); HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
HeapTupleHeaderSetXmax(tp.t_data, GetCurrentTransactionId()); HeapTupleHeaderSetXmax(tp.t_data, GetCurrentTransactionId());
HeapTupleHeaderSetCmax(tp.t_data, cid); HeapTupleHeaderSetCmax(tp.t_data, cid);
/* XLOG stuff */ /* XLOG stuff */
if (!relation->rd_istemp)
{ {
xl_heap_delete xlrec; xl_heap_delete xlrec;
XLogRecPtr recptr; XLogRecPtr recptr;
...@@ -1351,12 +1361,17 @@ l1: ...@@ -1351,12 +1361,17 @@ l1:
PageSetLSN(dp, recptr); PageSetLSN(dp, recptr);
PageSetSUI(dp, ThisStartUpID); PageSetSUI(dp, ThisStartUpID);
} }
else
{
/* No XLOG record, but still need to flag that XID exists on disk */
MyXactMadeTempRelUpdate = true;
}
END_CRIT_SECTION(); END_CRIT_SECTION();
LockBuffer(buffer, BUFFER_LOCK_UNLOCK); LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
#ifdef TUPLE_TOASTER_ACTIVE #ifdef TUPLE_TOASTER_ACTIVE
/* /*
* If the relation has toastable attributes, we need to delete no * If the relation has toastable attributes, we need to delete no
* longer needed items there too. We have to do this before * longer needed items there too. We have to do this before
...@@ -1659,6 +1674,7 @@ l2: ...@@ -1659,6 +1674,7 @@ l2:
oldtup.t_data->t_ctid = newtup->t_self; oldtup.t_data->t_ctid = newtup->t_self;
/* XLOG stuff */ /* XLOG stuff */
if (!relation->rd_istemp)
{ {
XLogRecPtr recptr = log_heap_update(relation, buffer, oldtup.t_self, XLogRecPtr recptr = log_heap_update(relation, buffer, oldtup.t_self,
newbuf, newtup, false); newbuf, newtup, false);
...@@ -1671,6 +1687,11 @@ l2: ...@@ -1671,6 +1687,11 @@ l2:
PageSetLSN(BufferGetPage(buffer), recptr); PageSetLSN(BufferGetPage(buffer), recptr);
PageSetSUI(BufferGetPage(buffer), ThisStartUpID); PageSetSUI(BufferGetPage(buffer), ThisStartUpID);
} }
else
{
/* No XLOG record, but still need to flag that XID exists on disk */
MyXactMadeTempRelUpdate = true;
}
END_CRIT_SECTION(); END_CRIT_SECTION();
...@@ -1927,6 +1948,9 @@ log_heap_clean(Relation reln, Buffer buffer, char *unused, int unlen) ...@@ -1927,6 +1948,9 @@ log_heap_clean(Relation reln, Buffer buffer, char *unused, int unlen)
XLogRecPtr recptr; XLogRecPtr recptr;
XLogRecData rdata[3]; XLogRecData rdata[3];
/* Caller should not call me on a temp relation */
Assert(!reln->rd_istemp);
xlrec.node = reln->rd_node; xlrec.node = reln->rd_node;
xlrec.block = BufferGetBlockNumber(buffer); xlrec.block = BufferGetBlockNumber(buffer);
rdata[0].buffer = InvalidBuffer; rdata[0].buffer = InvalidBuffer;
...@@ -1978,6 +2002,9 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from, ...@@ -1978,6 +2002,9 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
Page page = BufferGetPage(newbuf); Page page = BufferGetPage(newbuf);
uint8 info = (move) ? XLOG_HEAP_MOVE : XLOG_HEAP_UPDATE; uint8 info = (move) ? XLOG_HEAP_MOVE : XLOG_HEAP_UPDATE;
/* Caller should not call me on a temp relation */
Assert(!reln->rd_istemp);
xlrec.target.node = reln->rd_node; xlrec.target.node = reln->rd_node;
xlrec.target.tid = from; xlrec.target.tid = from;
xlrec.newtid = newtup->t_self; xlrec.newtid = newtup->t_self;
...@@ -2012,7 +2039,8 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from, ...@@ -2012,7 +2039,8 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
xid[0] = HeapTupleHeaderGetXmax(newtup->t_data); xid[0] = HeapTupleHeaderGetXmax(newtup->t_data);
xid[1] = HeapTupleHeaderGetXmin(newtup->t_data); xid[1] = HeapTupleHeaderGetXmin(newtup->t_data);
memcpy((char *) &xlhdr + hsize, memcpy((char *) &xlhdr + hsize,
(char *) xid, 2 * sizeof(TransactionId)); (char *) xid,
2 * sizeof(TransactionId));
hsize += 2 * sizeof(TransactionId); hsize += 2 * sizeof(TransactionId);
} }
rdata[2].buffer = newbuf; rdata[2].buffer = newbuf;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Id: hio.c,v 1.45 2002/06/20 20:29:25 momjian Exp $ * $Id: hio.c,v 1.46 2002/08/06 02:36:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -102,6 +102,7 @@ RelationGetBufferForTuple(Relation relation, Size len, ...@@ -102,6 +102,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
Size pageFreeSpace; Size pageFreeSpace;
BlockNumber targetBlock, BlockNumber targetBlock,
otherBlock; otherBlock;
bool needLock;
len = MAXALIGN(len); /* be conservative */ len = MAXALIGN(len); /* be conservative */
...@@ -231,9 +232,12 @@ RelationGetBufferForTuple(Relation relation, Size len, ...@@ -231,9 +232,12 @@ RelationGetBufferForTuple(Relation relation, Size len,
* *
* We have to use a lock to ensure no one else is extending the rel at * We have to use a lock to ensure no one else is extending the rel at
* the same time, else we will both try to initialize the same new * the same time, else we will both try to initialize the same new
* page. * page. We can skip locking for new or temp relations, however,
* since no one else could be accessing them.
*/ */
if (!relation->rd_myxactonly) needLock = !(relation->rd_isnew || relation->rd_istemp);
if (needLock)
LockPage(relation, 0, ExclusiveLock); LockPage(relation, 0, ExclusiveLock);
/* /*
...@@ -249,7 +253,7 @@ RelationGetBufferForTuple(Relation relation, Size len, ...@@ -249,7 +253,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
* Release the file-extension lock; it's now OK for someone else to * Release the file-extension lock; it's now OK for someone else to
* extend the relation some more. * extend the relation some more.
*/ */
if (!relation->rd_myxactonly) if (needLock)
UnlockPage(relation, 0, ExclusiveLock); UnlockPage(relation, 0, ExclusiveLock);
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.33 2002/07/20 05:16:56 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.34 2002/08/06 02:36:33 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -915,7 +915,7 @@ toast_save_datum(Relation rel, Datum value) ...@@ -915,7 +915,7 @@ toast_save_datum(Relation rel, Datum value)
*/ */
idxres = index_insert(toastidx, t_values, t_nulls, idxres = index_insert(toastidx, t_values, t_nulls,
&(toasttup->t_self), &(toasttup->t_self),
toastrel, toastidx->rd_uniqueindex); toastrel, toastidx->rd_index->indisunique);
if (idxres == NULL) if (idxres == NULL)
elog(ERROR, "Failed to insert index entry for TOAST tuple"); elog(ERROR, "Failed to insert index entry for TOAST tuple");
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.94 2002/07/02 05:48:44 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.95 2002/08/06 02:36:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -623,8 +623,11 @@ _bt_insertuple(Relation rel, Buffer buf, ...@@ -623,8 +623,11 @@ _bt_insertuple(Relation rel, Buffer buf,
BTPageOpaque pageop = (BTPageOpaque) PageGetSpecialPointer(page); BTPageOpaque pageop = (BTPageOpaque) PageGetSpecialPointer(page);
START_CRIT_SECTION(); START_CRIT_SECTION();
_bt_pgaddtup(rel, page, itemsz, btitem, newitemoff, "page"); _bt_pgaddtup(rel, page, itemsz, btitem, newitemoff, "page");
/* XLOG stuff */ /* XLOG stuff */
if (!rel->rd_istemp)
{ {
xl_btree_insert xlrec; xl_btree_insert xlrec;
uint8 flag = XLOG_BTREE_INSERT; uint8 flag = XLOG_BTREE_INSERT;
...@@ -866,6 +869,9 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright, ...@@ -866,6 +869,9 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
* NO ELOG(ERROR) till right sibling is updated. * NO ELOG(ERROR) till right sibling is updated.
*/ */
START_CRIT_SECTION(); START_CRIT_SECTION();
/* XLOG stuff */
if (!rel->rd_istemp)
{ {
xl_btree_split xlrec; xl_btree_split xlrec;
int flag = (newitemonleft) ? int flag = (newitemonleft) ?
...@@ -891,7 +897,7 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright, ...@@ -891,7 +897,7 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
BlockIdSet(&(xlrec.rightblk), ropaque->btpo_next); BlockIdSet(&(xlrec.rightblk), ropaque->btpo_next);
/* /*
* Dirrect access to page is not good but faster - we should * Direct access to page is not good but faster - we should
* implement some new func in page API. * implement some new func in page API.
*/ */
xlrec.leftlen = ((PageHeader) leftpage)->pd_special - xlrec.leftlen = ((PageHeader) leftpage)->pd_special -
...@@ -1352,6 +1358,7 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf) ...@@ -1352,6 +1358,7 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
(metad->btm_level)++; (metad->btm_level)++;
/* XLOG stuff */ /* XLOG stuff */
if (!rel->rd_istemp)
{ {
xl_btree_newroot xlrec; xl_btree_newroot xlrec;
XLogRecPtr recptr; XLogRecPtr recptr;
...@@ -1366,7 +1373,7 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf) ...@@ -1366,7 +1373,7 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
rdata[0].next = &(rdata[1]); rdata[0].next = &(rdata[1]);
/* /*
* Dirrect access to page is not good but faster - we should * Direct access to page is not good but faster - we should
* implement some new func in page API. * implement some new func in page API.
*/ */
rdata[1].buffer = InvalidBuffer; rdata[1].buffer = InvalidBuffer;
...@@ -1388,6 +1395,7 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf) ...@@ -1388,6 +1395,7 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
PageSetLSN(rpage, recptr); PageSetLSN(rpage, recptr);
PageSetSUI(rpage, ThisStartUpID); PageSetSUI(rpage, ThisStartUpID);
} }
END_CRIT_SECTION(); END_CRIT_SECTION();
/* write and let go of metapage buffer */ /* write and let go of metapage buffer */
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.57 2002/06/20 20:29:25 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.58 2002/08/06 02:36:33 tgl Exp $
* *
* NOTES * NOTES
* Postgres btree pages look like ordinary relation pages. The opaque * Postgres btree pages look like ordinary relation pages. The opaque
...@@ -173,6 +173,7 @@ _bt_getroot(Relation rel, int access) ...@@ -173,6 +173,7 @@ _bt_getroot(Relation rel, int access)
rootopaque->btpo_flags |= (BTP_LEAF | BTP_ROOT); rootopaque->btpo_flags |= (BTP_LEAF | BTP_ROOT);
/* XLOG stuff */ /* XLOG stuff */
if (!rel->rd_istemp)
{ {
xl_btree_newroot xlrec; xl_btree_newroot xlrec;
XLogRecPtr recptr; XLogRecPtr recptr;
...@@ -187,7 +188,8 @@ _bt_getroot(Relation rel, int access) ...@@ -187,7 +188,8 @@ _bt_getroot(Relation rel, int access)
rdata.next = NULL; rdata.next = NULL;
recptr = XLogInsert(RM_BTREE_ID, recptr = XLogInsert(RM_BTREE_ID,
XLOG_BTREE_NEWROOT | XLOG_BTREE_LEAF, &rdata); XLOG_BTREE_NEWROOT | XLOG_BTREE_LEAF,
&rdata);
PageSetLSN(rootpage, recptr); PageSetLSN(rootpage, recptr);
PageSetSUI(rootpage, ThisStartUpID); PageSetSUI(rootpage, ThisStartUpID);
...@@ -457,6 +459,7 @@ _bt_itemdel(Relation rel, Buffer buf, ItemPointer tid) ...@@ -457,6 +459,7 @@ _bt_itemdel(Relation rel, Buffer buf, ItemPointer tid)
PageIndexTupleDelete(page, offno); PageIndexTupleDelete(page, offno);
/* XLOG stuff */ /* XLOG stuff */
if (!rel->rd_istemp)
{ {
xl_btree_delete xlrec; xl_btree_delete xlrec;
XLogRecPtr recptr; XLogRecPtr recptr;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.129 2002/08/02 22:36:05 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.130 2002/08/06 02:36:33 tgl Exp $
* *
* NOTES * NOTES
* Transaction aborts can now occur two ways: * Transaction aborts can now occur two ways:
...@@ -505,44 +505,32 @@ AtStart_Memory(void) ...@@ -505,44 +505,32 @@ AtStart_Memory(void)
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
/* -------------------------------- /*
* RecordTransactionCommit * RecordTransactionCommit
*
* Note: the two calls to BufferManagerFlush() exist to ensure
* that data pages are written before log pages. These
* explicit calls should be replaced by a more efficient
* ordered page write scheme in the buffer manager
* -cim 3/18/90
* --------------------------------
*/ */
void void
RecordTransactionCommit(void) RecordTransactionCommit(void)
{ {
TransactionId xid;
bool leak;
leak = BufferPoolCheckLeak();
xid = GetCurrentTransactionId();
/* /*
* We only need to log the commit in xlog and clog if the transaction made * If we made neither any XLOG entries nor any temp-rel updates,
* any transaction-controlled XLOG entries. (Otherwise, its XID appears * we can omit recording the transaction commit at all.
* nowhere in permanent storage, so no one will ever care if it
* committed.) However, we must flush XLOG to disk if we made any XLOG
* entries, whether in or out of transaction control. For example, if we
* reported a nextval() result to the client, this ensures that any XLOG
* record generated by nextval will hit the disk before we report the
* transaction committed.
*/ */
if (MyXactMadeXLogEntry) if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate)
{ {
TransactionId xid = GetCurrentTransactionId();
XLogRecPtr recptr; XLogRecPtr recptr;
/* Tell bufmgr and smgr to prepare for commit */
BufmgrCommit(); BufmgrCommit();
START_CRIT_SECTION(); START_CRIT_SECTION();
/*
* We only need to log the commit in xlog if the transaction made any
* transaction-controlled XLOG entries. (Otherwise, its XID appears
* nowhere in permanent storage, so no one else will ever care if it
* committed.)
*/
if (MyLastRecPtr.xrecoff != 0) if (MyLastRecPtr.xrecoff != 0)
{ {
/* Need to emit a commit record */ /* Need to emit a commit record */
...@@ -567,30 +555,48 @@ RecordTransactionCommit(void) ...@@ -567,30 +555,48 @@ RecordTransactionCommit(void)
} }
/* /*
* Sleep before flush! So we can flush more than one commit * We must flush our XLOG entries to disk if we made any XLOG entries,
* records per single fsync. (The idea is some other backend may * whether in or out of transaction control. For example, if we
* do the XLogFlush while we're sleeping. This needs work still, * reported a nextval() result to the client, this ensures that any
* because on most Unixen, the minimum select() delay is 10msec or * XLOG record generated by nextval will hit the disk before we report
* more, which is way too long.) * the transaction committed.
*
* We do not sleep if enableFsync is not turned on, nor if there are
* fewer than CommitSiblings other backends with active
* transactions.
*/ */
if (CommitDelay > 0 && enableFsync && if (MyXactMadeXLogEntry)
CountActiveBackends() >= CommitSiblings)
{ {
struct timeval delay; /*
* Sleep before flush! So we can flush more than one commit
* records per single fsync. (The idea is some other backend may
* do the XLogFlush while we're sleeping. This needs work still,
* because on most Unixen, the minimum select() delay is 10msec or
* more, which is way too long.)
*
* We do not sleep if enableFsync is not turned on, nor if there
* are fewer than CommitSiblings other backends with active
* transactions.
*/
if (CommitDelay > 0 && enableFsync &&
CountActiveBackends() >= CommitSiblings)
{
struct timeval delay;
delay.tv_sec = 0; delay.tv_sec = 0;
delay.tv_usec = CommitDelay; delay.tv_usec = CommitDelay;
(void) select(0, NULL, NULL, NULL, &delay); (void) select(0, NULL, NULL, NULL, &delay);
} }
XLogFlush(recptr); XLogFlush(recptr);
}
/* Mark the transaction committed in clog, if needed */ /*
if (MyLastRecPtr.xrecoff != 0) * We must mark the transaction committed in clog if its XID appears
* either in permanent rels or in local temporary rels. We test
* this by seeing if we made transaction-controlled entries *OR*
* local-rel tuple updates. Note that if we made only the latter,
* we have not emitted an XLOG record for our commit, and so in the
* event of a crash the clog update might be lost. This is okay
* because no one else will ever care whether we committed.
*/
if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
TransactionIdCommit(xid); TransactionIdCommit(xid);
END_CRIT_SECTION(); END_CRIT_SECTION();
...@@ -599,12 +605,10 @@ RecordTransactionCommit(void) ...@@ -599,12 +605,10 @@ RecordTransactionCommit(void)
/* Break the chain of back-links in the XLOG records I output */ /* Break the chain of back-links in the XLOG records I output */
MyLastRecPtr.xrecoff = 0; MyLastRecPtr.xrecoff = 0;
MyXactMadeXLogEntry = false; MyXactMadeXLogEntry = false;
MyXactMadeTempRelUpdate = false;
/* Show myself as out of the transaction in PGPROC array */ /* Show myself as out of the transaction in PGPROC array */
MyProc->logRec.xrecoff = 0; MyProc->logRec.xrecoff = 0;
if (leak)
ResetBufferPool(true);
} }
...@@ -615,8 +619,10 @@ RecordTransactionCommit(void) ...@@ -615,8 +619,10 @@ RecordTransactionCommit(void)
static void static void
AtCommit_Cache(void) AtCommit_Cache(void)
{ {
/* Check for relcache reference-count leaks */ /*
AtEOXactRelationCache(true); * Clean up the relation cache.
*/
AtEOXact_RelationCache(true);
/* /*
* Make catalog changes visible to all backends. * Make catalog changes visible to all backends.
*/ */
...@@ -679,45 +685,60 @@ AtCommit_Memory(void) ...@@ -679,45 +685,60 @@ AtCommit_Memory(void)
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
/* -------------------------------- /*
* RecordTransactionAbort * RecordTransactionAbort
* --------------------------------
*/ */
static void static void
RecordTransactionAbort(void) RecordTransactionAbort(void)
{ {
TransactionId xid = GetCurrentTransactionId();
/* /*
* We only need to log the abort in xlog and clog if the transaction made * If we made neither any transaction-controlled XLOG entries nor any
* any transaction-controlled XLOG entries. (Otherwise, its XID appears * temp-rel updates, we can omit recording the transaction abort at all.
* nowhere in permanent storage, so no one will ever care if it * No one will ever care that it aborted.
* committed.) We do not flush XLOG to disk in any case, since the
* default assumption after a crash would be that we aborted, anyway.
*
* Extra check here is to catch case that we aborted partway through
* RecordTransactionCommit ...
*/ */
if (MyLastRecPtr.xrecoff != 0 && !TransactionIdDidCommit(xid)) if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
{ {
XLogRecData rdata; TransactionId xid = GetCurrentTransactionId();
xl_xact_abort xlrec;
XLogRecPtr recptr;
xlrec.xtime = time(NULL); /*
rdata.buffer = InvalidBuffer; * Catch the scenario where we aborted partway through
rdata.data = (char *) (&xlrec); * RecordTransactionCommit ...
rdata.len = SizeOfXactAbort; */
rdata.next = NULL; if (TransactionIdDidCommit(xid))
elog(PANIC, "RecordTransactionAbort: xact %u already committed",
xid);
START_CRIT_SECTION(); START_CRIT_SECTION();
/* /*
* SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP * We only need to log the abort in XLOG if the transaction made any
* transaction-controlled XLOG entries. (Otherwise, its XID appears
* nowhere in permanent storage, so no one else will ever care if it
* committed.) We do not flush XLOG to disk in any case, since the
* default assumption after a crash would be that we aborted, anyway.
*/ */
recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, &rdata); if (MyLastRecPtr.xrecoff != 0)
{
XLogRecData rdata;
xl_xact_abort xlrec;
XLogRecPtr recptr;
xlrec.xtime = time(NULL);
rdata.buffer = InvalidBuffer;
rdata.data = (char *) (&xlrec);
rdata.len = SizeOfXactAbort;
rdata.next = NULL;
/*
* SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
*/
recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, &rdata);
}
/* Mark the transaction aborted in clog */ /*
* Mark the transaction aborted in clog. This is not absolutely
* necessary but we may as well do it while we are here.
*/
TransactionIdAbort(xid); TransactionIdAbort(xid);
END_CRIT_SECTION(); END_CRIT_SECTION();
...@@ -726,14 +747,10 @@ RecordTransactionAbort(void) ...@@ -726,14 +747,10 @@ RecordTransactionAbort(void)
/* Break the chain of back-links in the XLOG records I output */ /* Break the chain of back-links in the XLOG records I output */
MyLastRecPtr.xrecoff = 0; MyLastRecPtr.xrecoff = 0;
MyXactMadeXLogEntry = false; MyXactMadeXLogEntry = false;
MyXactMadeTempRelUpdate = false;
/* Show myself as out of the transaction in PGPROC array */ /* Show myself as out of the transaction in PGPROC array */
MyProc->logRec.xrecoff = 0; MyProc->logRec.xrecoff = 0;
/*
* Tell bufmgr and smgr to release resources.
*/
ResetBufferPool(false); /* false -> is abort */
} }
/* -------------------------------- /* --------------------------------
...@@ -743,7 +760,7 @@ RecordTransactionAbort(void) ...@@ -743,7 +760,7 @@ RecordTransactionAbort(void)
static void static void
AtAbort_Cache(void) AtAbort_Cache(void)
{ {
AtEOXactRelationCache(false); AtEOXact_RelationCache(false);
AtEOXactInvalidationMessages(false); AtEOXactInvalidationMessages(false);
} }
...@@ -975,7 +992,6 @@ CommitTransaction(void) ...@@ -975,7 +992,6 @@ CommitTransaction(void)
* noncritical resource releasing. * noncritical resource releasing.
*/ */
RelationPurgeLocalRelation(true);
smgrDoPendingDeletes(true); smgrDoPendingDeletes(true);
AtEOXact_GUC(true); AtEOXact_GUC(true);
...@@ -989,6 +1005,8 @@ CommitTransaction(void) ...@@ -989,6 +1005,8 @@ CommitTransaction(void)
AtCommit_Locks(); AtCommit_Locks();
AtEOXact_CatCache(true); AtEOXact_CatCache(true);
AtCommit_Memory(); AtCommit_Memory();
AtEOXact_Buffers(true);
smgrabort();
AtEOXact_Files(); AtEOXact_Files();
/* Count transaction commit in statistics collector */ /* Count transaction commit in statistics collector */
...@@ -1076,7 +1094,6 @@ AbortTransaction(void) ...@@ -1076,7 +1094,6 @@ AbortTransaction(void)
LWLockRelease(SInvalLock); LWLockRelease(SInvalLock);
} }
RelationPurgeLocalRelation(false);
smgrDoPendingDeletes(false); smgrDoPendingDeletes(false);
AtEOXact_GUC(false); AtEOXact_GUC(false);
...@@ -1089,6 +1106,7 @@ AbortTransaction(void) ...@@ -1089,6 +1106,7 @@ AbortTransaction(void)
AtAbort_Cache(); AtAbort_Cache();
AtEOXact_CatCache(false); AtEOXact_CatCache(false);
AtAbort_Memory(); AtAbort_Memory();
AtEOXact_Buffers(false);
AtEOXact_Files(); AtEOXact_Files();
AtAbort_Locks(); AtAbort_Locks();
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.100 2002/08/05 01:24:13 thomas Exp $ * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.101 2002/08/06 02:36:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -136,11 +136,20 @@ bool InRecovery = false; ...@@ -136,11 +136,20 @@ bool InRecovery = false;
* to be set true. The latter can be used to test whether the current xact * to be set true. The latter can be used to test whether the current xact
* made any loggable changes (including out-of-xact changes, such as * made any loggable changes (including out-of-xact changes, such as
* sequence updates). * sequence updates).
*
* When we insert/update/delete a tuple in a temporary relation, we do not
* make any XLOG record, since we don't care about recovering the state of
* the temp rel after a crash. However, we will still need to remember
* whether our transaction committed or aborted in that case. So, we must
* set MyXactMadeTempRelUpdate true to indicate that the XID will be of
* interest later.
*/ */
XLogRecPtr MyLastRecPtr = {0, 0}; XLogRecPtr MyLastRecPtr = {0, 0};
bool MyXactMadeXLogEntry = false; bool MyXactMadeXLogEntry = false;
bool MyXactMadeTempRelUpdate = false;
/* /*
* ProcLastRecPtr points to the start of the last XLOG record inserted by the * ProcLastRecPtr points to the start of the last XLOG record inserted by the
* current backend. It is updated for all inserts, transaction-controlled * current backend. It is updated for all inserts, transaction-controlled
...@@ -2923,6 +2932,7 @@ ShutdownXLOG(void) ...@@ -2923,6 +2932,7 @@ ShutdownXLOG(void)
/* suppress in-transaction check in CreateCheckPoint */ /* suppress in-transaction check in CreateCheckPoint */
MyLastRecPtr.xrecoff = 0; MyLastRecPtr.xrecoff = 0;
MyXactMadeXLogEntry = false; MyXactMadeXLogEntry = false;
MyXactMadeTempRelUpdate = false;
CritSectionCount++; CritSectionCount++;
CreateDummyCaches(); CreateDummyCaches();
...@@ -3084,12 +3094,10 @@ CreateCheckPoint(bool shutdown) ...@@ -3084,12 +3094,10 @@ CreateCheckPoint(bool shutdown)
/* /*
* Having constructed the checkpoint record, ensure all shmem disk * Having constructed the checkpoint record, ensure all shmem disk
* buffers are flushed to disk. * buffers and commit-log buffers are flushed to disk.
*/ */
FlushBufferPool();
/* And commit-log buffers, too */
CheckPointCLOG(); CheckPointCLOG();
FlushBufferPool();
/* /*
* Now insert the checkpoint record into XLOG. * Now insert the checkpoint record into XLOG.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.218 2002/08/05 03:29:16 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.219 2002/08/06 02:36:33 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -1919,7 +1919,7 @@ heap_truncate(Oid rid) ...@@ -1919,7 +1919,7 @@ heap_truncate(Oid rid)
* a rel created in the current xact (which would be deleted on abort, * a rel created in the current xact (which would be deleted on abort,
* anyway). * anyway).
*/ */
if (IsTransactionBlock() && !rel->rd_myxactonly) if (IsTransactionBlock() && !rel->rd_isnew)
elog(ERROR, "TRUNCATE TABLE cannot run inside a transaction block"); elog(ERROR, "TRUNCATE TABLE cannot run inside a transaction block");
/* /*
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.100 2002/08/05 03:29:16 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.101 2002/08/06 02:36:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -121,7 +121,7 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple) ...@@ -121,7 +121,7 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple)
nullv, /* info on nulls */ nullv, /* info on nulls */
&(heapTuple->t_self), /* tid of heap tuple */ &(heapTuple->t_self), /* tid of heap tuple */
heapRelation, heapRelation,
relationDescs[i]->rd_uniqueindex); relationDescs[i]->rd_index->indisunique);
if (result) if (result)
pfree(result); pfree(result);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.83 2002/07/16 22:12:19 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.84 2002/08/06 02:36:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -237,6 +237,7 @@ DefineSequence(CreateSeqStmt *seq) ...@@ -237,6 +237,7 @@ DefineSequence(CreateSeqStmt *seq)
* means two log records instead of one :-( * means two log records instead of one :-(
*/ */
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
START_CRIT_SECTION(); START_CRIT_SECTION();
{ {
...@@ -260,6 +261,8 @@ DefineSequence(CreateSeqStmt *seq) ...@@ -260,6 +261,8 @@ DefineSequence(CreateSeqStmt *seq)
tuple->t_data->t_infomask |= HEAP_XMIN_COMMITTED; tuple->t_data->t_infomask |= HEAP_XMIN_COMMITTED;
} }
/* XLOG stuff */
if (!rel->rd_istemp)
{ {
xl_seq_rec xlrec; xl_seq_rec xlrec;
XLogRecPtr recptr; XLogRecPtr recptr;
...@@ -287,6 +290,7 @@ DefineSequence(CreateSeqStmt *seq) ...@@ -287,6 +290,7 @@ DefineSequence(CreateSeqStmt *seq)
PageSetLSN(page, recptr); PageSetLSN(page, recptr);
PageSetSUI(page, ThisStartUpID); PageSetSUI(page, ThisStartUpID);
} }
END_CRIT_SECTION(); END_CRIT_SECTION();
LockBuffer(buf, BUFFER_LOCK_UNLOCK); LockBuffer(buf, BUFFER_LOCK_UNLOCK);
...@@ -437,7 +441,9 @@ nextval(PG_FUNCTION_ARGS) ...@@ -437,7 +441,9 @@ nextval(PG_FUNCTION_ARGS)
elm->cached = last; /* last fetched number */ elm->cached = last; /* last fetched number */
START_CRIT_SECTION(); START_CRIT_SECTION();
if (logit)
/* XLOG stuff */
if (logit && !seqrel->rd_istemp)
{ {
xl_seq_rec xlrec; xl_seq_rec xlrec;
XLogRecPtr recptr; XLogRecPtr recptr;
...@@ -449,9 +455,11 @@ nextval(PG_FUNCTION_ARGS) ...@@ -449,9 +455,11 @@ nextval(PG_FUNCTION_ARGS)
rdata[0].len = sizeof(xl_seq_rec); rdata[0].len = sizeof(xl_seq_rec);
rdata[0].next = &(rdata[1]); rdata[0].next = &(rdata[1]);
/* set values that will be saved in xlog */
seq->last_value = next; seq->last_value = next;
seq->is_called = true; seq->is_called = true;
seq->log_cnt = 0; seq->log_cnt = 0;
rdata[1].buffer = InvalidBuffer; rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper; rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
rdata[1].len = ((PageHeader) page)->pd_special - rdata[1].len = ((PageHeader) page)->pd_special -
...@@ -468,6 +476,7 @@ nextval(PG_FUNCTION_ARGS) ...@@ -468,6 +476,7 @@ nextval(PG_FUNCTION_ARGS)
seq->last_value = last; /* last fetched number */ seq->last_value = last; /* last fetched number */
seq->is_called = true; seq->is_called = true;
seq->log_cnt = log; /* how much is logged */ seq->log_cnt = log; /* how much is logged */
END_CRIT_SECTION(); END_CRIT_SECTION();
LockBuffer(buf, BUFFER_LOCK_UNLOCK); LockBuffer(buf, BUFFER_LOCK_UNLOCK);
...@@ -550,6 +559,9 @@ do_setval(RangeVar *sequence, int64 next, bool iscalled) ...@@ -550,6 +559,9 @@ do_setval(RangeVar *sequence, int64 next, bool iscalled)
* values) */ * values) */
START_CRIT_SECTION(); START_CRIT_SECTION();
/* XLOG stuff */
if (!seqrel->rd_istemp)
{ {
xl_seq_rec xlrec; xl_seq_rec xlrec;
XLogRecPtr recptr; XLogRecPtr recptr;
...@@ -562,9 +574,11 @@ do_setval(RangeVar *sequence, int64 next, bool iscalled) ...@@ -562,9 +574,11 @@ do_setval(RangeVar *sequence, int64 next, bool iscalled)
rdata[0].len = sizeof(xl_seq_rec); rdata[0].len = sizeof(xl_seq_rec);
rdata[0].next = &(rdata[1]); rdata[0].next = &(rdata[1]);
/* set values that will be saved in xlog */
seq->last_value = next; seq->last_value = next;
seq->is_called = true; seq->is_called = true;
seq->log_cnt = 0; seq->log_cnt = 0;
rdata[1].buffer = InvalidBuffer; rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper; rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
rdata[1].len = ((PageHeader) page)->pd_special - rdata[1].len = ((PageHeader) page)->pd_special -
...@@ -576,10 +590,12 @@ do_setval(RangeVar *sequence, int64 next, bool iscalled) ...@@ -576,10 +590,12 @@ do_setval(RangeVar *sequence, int64 next, bool iscalled)
PageSetLSN(page, recptr); PageSetLSN(page, recptr);
PageSetSUI(page, ThisStartUpID); PageSetSUI(page, ThisStartUpID);
} }
/* save info in sequence relation */ /* save info in sequence relation */
seq->last_value = next; /* last fetched number */ seq->last_value = next; /* last fetched number */
seq->is_called = iscalled; seq->is_called = iscalled;
seq->log_cnt = (iscalled) ? 0 : 1; seq->log_cnt = (iscalled) ? 0 : 1;
END_CRIT_SECTION(); END_CRIT_SECTION();
LockBuffer(buf, BUFFER_LOCK_UNLOCK); LockBuffer(buf, BUFFER_LOCK_UNLOCK);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.232 2002/07/20 05:16:57 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.233 2002/08/06 02:36:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1899,6 +1899,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -1899,6 +1899,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
newtup.t_data = (HeapTupleHeader) PageGetItem(ToPage, newitemid); newtup.t_data = (HeapTupleHeader) PageGetItem(ToPage, newitemid);
ItemPointerSet(&(newtup.t_self), destvacpage->blkno, newoff); ItemPointerSet(&(newtup.t_self), destvacpage->blkno, newoff);
/* XLOG stuff */
if (!onerel->rd_istemp)
{ {
XLogRecPtr recptr = XLogRecPtr recptr =
log_heap_move(onerel, Cbuf, tuple.t_self, log_heap_move(onerel, Cbuf, tuple.t_self,
...@@ -1912,6 +1914,12 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -1912,6 +1914,12 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
PageSetLSN(ToPage, recptr); PageSetLSN(ToPage, recptr);
PageSetSUI(ToPage, ThisStartUpID); PageSetSUI(ToPage, ThisStartUpID);
} }
else
{
/* No XLOG record, but still need to flag that XID exists on disk */
MyXactMadeTempRelUpdate = true;
}
END_CRIT_SECTION(); END_CRIT_SECTION();
if (destvacpage->blkno > last_move_dest_block) if (destvacpage->blkno > last_move_dest_block)
...@@ -2042,6 +2050,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -2042,6 +2050,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
tuple.t_data->t_infomask |= HEAP_MOVED_OFF; tuple.t_data->t_infomask |= HEAP_MOVED_OFF;
HeapTupleHeaderSetXvac(tuple.t_data, myXID); HeapTupleHeaderSetXvac(tuple.t_data, myXID);
/* XLOG stuff */
if (!onerel->rd_istemp)
{ {
XLogRecPtr recptr = XLogRecPtr recptr =
log_heap_move(onerel, buf, tuple.t_self, log_heap_move(onerel, buf, tuple.t_self,
...@@ -2052,6 +2062,12 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -2052,6 +2062,12 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
PageSetLSN(ToPage, recptr); PageSetLSN(ToPage, recptr);
PageSetSUI(ToPage, ThisStartUpID); PageSetSUI(ToPage, ThisStartUpID);
} }
else
{
/* No XLOG record, but still need to flag that XID exists on disk */
MyXactMadeTempRelUpdate = true;
}
END_CRIT_SECTION(); END_CRIT_SECTION();
cur_page->offsets_used++; cur_page->offsets_used++;
...@@ -2321,8 +2337,13 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -2321,8 +2337,13 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
} }
Assert(vacpage->offsets_free == num_tuples); Assert(vacpage->offsets_free == num_tuples);
START_CRIT_SECTION(); START_CRIT_SECTION();
uncnt = PageRepairFragmentation(page, unused); uncnt = PageRepairFragmentation(page, unused);
/* XLOG stuff */
if (!onerel->rd_istemp)
{ {
XLogRecPtr recptr; XLogRecPtr recptr;
...@@ -2331,7 +2352,14 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -2331,7 +2352,14 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
PageSetLSN(page, recptr); PageSetLSN(page, recptr);
PageSetSUI(page, ThisStartUpID); PageSetSUI(page, ThisStartUpID);
} }
else
{
/* No XLOG record, but still need to flag that XID exists on disk */
MyXactMadeTempRelUpdate = true;
}
END_CRIT_SECTION(); END_CRIT_SECTION();
LockBuffer(buf, BUFFER_LOCK_UNLOCK); LockBuffer(buf, BUFFER_LOCK_UNLOCK);
WriteBuffer(buf); WriteBuffer(buf);
} }
...@@ -2450,12 +2478,17 @@ vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage) ...@@ -2450,12 +2478,17 @@ vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage)
Assert(vacpage->offsets_used == 0); Assert(vacpage->offsets_used == 0);
START_CRIT_SECTION(); START_CRIT_SECTION();
for (i = 0; i < vacpage->offsets_free; i++) for (i = 0; i < vacpage->offsets_free; i++)
{ {
itemid = PageGetItemId(page, vacpage->offsets[i]); itemid = PageGetItemId(page, vacpage->offsets[i]);
itemid->lp_flags &= ~LP_USED; itemid->lp_flags &= ~LP_USED;
} }
uncnt = PageRepairFragmentation(page, unused); uncnt = PageRepairFragmentation(page, unused);
/* XLOG stuff */
if (!onerel->rd_istemp)
{ {
XLogRecPtr recptr; XLogRecPtr recptr;
...@@ -2464,6 +2497,12 @@ vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage) ...@@ -2464,6 +2497,12 @@ vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage)
PageSetLSN(page, recptr); PageSetLSN(page, recptr);
PageSetSUI(page, ThisStartUpID); PageSetSUI(page, ThisStartUpID);
} }
else
{
/* No XLOG record, but still need to flag that XID exists on disk */
MyXactMadeTempRelUpdate = true;
}
END_CRIT_SECTION(); END_CRIT_SECTION();
} }
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.17 2002/07/20 05:16:57 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.18 2002/08/06 02:36:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -523,6 +523,8 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer, ...@@ -523,6 +523,8 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
uncnt = PageRepairFragmentation(page, unused); uncnt = PageRepairFragmentation(page, unused);
/* XLOG stuff */
if (!onerel->rd_istemp)
{ {
XLogRecPtr recptr; XLogRecPtr recptr;
...@@ -531,6 +533,12 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer, ...@@ -531,6 +533,12 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
PageSetLSN(page, recptr); PageSetLSN(page, recptr);
PageSetSUI(page, ThisStartUpID); PageSetSUI(page, ThisStartUpID);
} }
else
{
/* No XLOG record, but still need to flag that XID exists on disk */
MyXactMadeTempRelUpdate = true;
}
END_CRIT_SECTION(); END_CRIT_SECTION();
return tupindex; return tupindex;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.87 2002/07/20 05:16:58 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.88 2002/08/06 02:36:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -691,7 +691,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot, ...@@ -691,7 +691,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
nullv, /* info on nulls */ nullv, /* info on nulls */
&(heapTuple->t_self), /* tid of heap tuple */ &(heapTuple->t_self), /* tid of heap tuple */
heapRelation, heapRelation,
relationDescs[i]->rd_uniqueindex && !is_vacuum); relationDescs[i]->rd_index->indisunique && !is_vacuum);
/* /*
* keep track of index inserts for debugging * keep track of index inserts for debugging
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.49 2002/06/20 20:29:34 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.50 2002/08/06 02:36:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -258,7 +258,7 @@ ShutdownBufferPoolAccess(void) ...@@ -258,7 +258,7 @@ ShutdownBufferPoolAccess(void)
/* Release any buffer context locks we are holding */ /* Release any buffer context locks we are holding */
UnlockBuffers(); UnlockBuffers();
/* Release any buffer reference counts we are holding */ /* Release any buffer reference counts we are holding */
ResetBufferPool(false); AtEOXact_Buffers(false);
} }
/* ----------------------------------------------------- /* -----------------------------------------------------
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.127 2002/07/02 05:47:37 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.128 2002/08/06 02:36:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -57,16 +57,9 @@ ...@@ -57,16 +57,9 @@
#include "pgstat.h" #include "pgstat.h"
#define BufferGetLSN(bufHdr) \ #define BufferGetLSN(bufHdr) \
(*((XLogRecPtr*)MAKE_PTR((bufHdr)->data))) (*((XLogRecPtr*) MAKE_PTR((bufHdr)->data)))
extern long int ReadBufferCount;
extern long int ReadLocalBufferCount;
extern long int BufferHitCount;
extern long int LocalBufferHitCount;
extern long int BufferFlushCount;
extern long int LocalBufferFlushCount;
static void WaitIO(BufferDesc *buf); static void WaitIO(BufferDesc *buf);
static void StartBufferIO(BufferDesc *buf, bool forInput); static void StartBufferIO(BufferDesc *buf, bool forInput);
static void TerminateBufferIO(BufferDesc *buf); static void TerminateBufferIO(BufferDesc *buf);
...@@ -82,16 +75,12 @@ static Buffer ReadBufferInternal(Relation reln, BlockNumber blockNum, ...@@ -82,16 +75,12 @@ static Buffer ReadBufferInternal(Relation reln, BlockNumber blockNum,
bool bufferLockHeld); bool bufferLockHeld);
static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum, static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum,
bool *foundPtr); bool *foundPtr);
static int ReleaseBufferWithBufferLock(Buffer buffer);
static int BufferReplace(BufferDesc *bufHdr); static int BufferReplace(BufferDesc *bufHdr);
#ifdef NOT_USED #ifdef NOT_USED
void PrintBufferDescs(void); void PrintBufferDescs(void);
#endif #endif
static void write_buffer(Buffer buffer, bool unpin); static void write_buffer(Buffer buffer, bool unpin);
static void drop_relfilenode_buffers(RelFileNode rnode,
bool do_local, bool do_both);
static int release_buffer(Buffer buffer, bool havelock);
/* /*
* ReadBuffer -- returns a buffer containing the requested * ReadBuffer -- returns a buffer containing the requested
...@@ -140,7 +129,7 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum, ...@@ -140,7 +129,7 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum,
bool isLocalBuf; bool isLocalBuf;
isExtend = (blockNum == P_NEW); isExtend = (blockNum == P_NEW);
isLocalBuf = reln->rd_myxactonly; isLocalBuf = reln->rd_istemp;
if (isLocalBuf) if (isLocalBuf)
{ {
...@@ -684,10 +673,10 @@ ReleaseAndReadBuffer(Buffer buffer, ...@@ -684,10 +673,10 @@ ReleaseAndReadBuffer(Buffer buffer,
/* /*
* BufferSync -- Write all dirty buffers in the pool. * BufferSync -- Write all dirty buffers in the pool.
* *
* This is called at checkpoint time and write out all dirty buffers. * This is called at checkpoint time and writes out all dirty shared buffers.
*/ */
void void
BufferSync() BufferSync(void)
{ {
int i; int i;
BufferDesc *bufHdr; BufferDesc *bufHdr;
...@@ -780,8 +769,7 @@ BufferSync() ...@@ -780,8 +769,7 @@ BufferSync()
status = smgrblindwrt(DEFAULT_SMGR, status = smgrblindwrt(DEFAULT_SMGR,
bufHdr->tag.rnode, bufHdr->tag.rnode,
bufHdr->tag.blockNum, bufHdr->tag.blockNum,
(char *) MAKE_PTR(bufHdr->data), (char *) MAKE_PTR(bufHdr->data));
true); /* must fsync */
} }
else else
{ {
...@@ -908,19 +896,16 @@ ResetBufferUsage(void) ...@@ -908,19 +896,16 @@ ResetBufferUsage(void)
NDirectFileWrite = 0; NDirectFileWrite = 0;
} }
/* ---------------------------------------------- /*
* ResetBufferPool * AtEOXact_Buffers - clean up at end of transaction.
*
* This routine is supposed to be called when a transaction aborts.
* It will release all the buffer pins held by the transaction.
* Currently, we also call it during commit if BufferPoolCheckLeak
* detected a problem --- in that case, isCommit is TRUE, and we
* only clean up buffer pin counts.
* *
* ---------------------------------------------- * During abort, we need to release any buffer pins we're holding
* (this cleans up in case elog interrupted a routine that pins a
* buffer). During commit, we shouldn't need to do that, but check
* anyway to see if anyone leaked a buffer reference count.
*/ */
void void
ResetBufferPool(bool isCommit) AtEOXact_Buffers(bool isCommit)
{ {
int i; int i;
...@@ -928,7 +913,16 @@ ResetBufferPool(bool isCommit) ...@@ -928,7 +913,16 @@ ResetBufferPool(bool isCommit)
{ {
if (PrivateRefCount[i] != 0) if (PrivateRefCount[i] != 0)
{ {
BufferDesc *buf = &BufferDescriptors[i]; BufferDesc *buf = &(BufferDescriptors[i]);
if (isCommit)
elog(WARNING,
"Buffer Leak: [%03d] (freeNext=%d, freePrev=%d, "
"rel=%u/%u, blockNum=%u, flags=0x%x, refcount=%d %ld)",
i, buf->freeNext, buf->freePrev,
buf->tag.rnode.tblNode, buf->tag.rnode.relNode,
buf->tag.blockNum, buf->flags,
buf->refcount, PrivateRefCount[i]);
PrivateRefCount[i] = 1; /* make sure we release shared pin */ PrivateRefCount[i] = 1; /* make sure we release shared pin */
LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
...@@ -938,48 +932,15 @@ ResetBufferPool(bool isCommit) ...@@ -938,48 +932,15 @@ ResetBufferPool(bool isCommit)
} }
} }
ResetLocalBufferPool(); AtEOXact_LocalBuffers(isCommit);
if (!isCommit)
smgrabort();
} }
/* /*
* BufferPoolCheckLeak
*
* check if there is buffer leak
*/
bool
BufferPoolCheckLeak(void)
{
int i;
bool result = false;
for (i = 0; i < NBuffers; i++)
{
if (PrivateRefCount[i] != 0)
{
BufferDesc *buf = &(BufferDescriptors[i]);
elog(WARNING,
"Buffer Leak: [%03d] (freeNext=%d, freePrev=%d, \
rel=%u/%u, blockNum=%u, flags=0x%x, refcount=%d %ld)",
i, buf->freeNext, buf->freePrev,
buf->tag.rnode.tblNode, buf->tag.rnode.relNode,
buf->tag.blockNum, buf->flags,
buf->refcount, PrivateRefCount[i]);
result = true;
}
}
return result;
}
/* ------------------------------------------------
* FlushBufferPool * FlushBufferPool
* *
* Flush all dirty blocks in buffer pool to disk * Flush all dirty blocks in buffer pool to disk at the checkpoint time.
* at the checkpoint time * Local relations do not participate in checkpoints, so they don't need to be
* ------------------------------------------------ * flushed.
*/ */
void void
FlushBufferPool(void) FlushBufferPool(void)
...@@ -989,16 +950,13 @@ FlushBufferPool(void) ...@@ -989,16 +950,13 @@ FlushBufferPool(void)
} }
/* /*
* At the commit time we have to flush local buffer pool only * Do whatever is needed to prepare for commit at the bufmgr and smgr levels
*/ */
void void
BufmgrCommit(void) BufmgrCommit(void)
{ {
LocalBufferSync(); /* Nothing to do in bufmgr anymore... */
/*
* All files created in current transaction will be fsync-ed
*/
smgrcommit(); smgrcommit();
} }
...@@ -1051,15 +1009,15 @@ BufferReplace(BufferDesc *bufHdr) ...@@ -1051,15 +1009,15 @@ BufferReplace(BufferDesc *bufHdr)
if (reln != (Relation) NULL) if (reln != (Relation) NULL)
{ {
status = smgrwrite(DEFAULT_SMGR, reln, bufHdr->tag.blockNum, status = smgrwrite(DEFAULT_SMGR, reln,
bufHdr->tag.blockNum,
(char *) MAKE_PTR(bufHdr->data)); (char *) MAKE_PTR(bufHdr->data));
} }
else else
{ {
status = smgrblindwrt(DEFAULT_SMGR, bufHdr->tag.rnode, status = smgrblindwrt(DEFAULT_SMGR, bufHdr->tag.rnode,
bufHdr->tag.blockNum, bufHdr->tag.blockNum,
(char *) MAKE_PTR(bufHdr->data), (char *) MAKE_PTR(bufHdr->data));
false); /* no fsync */
} }
/* drop relcache refcnt incremented by RelationNodeCacheGetRelation */ /* drop relcache refcnt incremented by RelationNodeCacheGetRelation */
...@@ -1091,31 +1049,55 @@ RelationGetNumberOfBlocks(Relation relation) ...@@ -1091,31 +1049,55 @@ RelationGetNumberOfBlocks(Relation relation)
{ {
/* /*
* relation->rd_nblocks should be accurate already if the relation is * relation->rd_nblocks should be accurate already if the relation is
* myxactonly. (XXX how safe is that really?) Don't call smgr on a * new or temp, because no one else should be modifying it. Otherwise
* view, either. * we need to ask the smgr for the current physical file length.
*
* Don't call smgr on a view, either.
*/ */
if (relation->rd_rel->relkind == RELKIND_VIEW) if (relation->rd_rel->relkind == RELKIND_VIEW)
relation->rd_nblocks = 0; relation->rd_nblocks = 0;
else if (!relation->rd_myxactonly) else if (!relation->rd_isnew && !relation->rd_istemp)
relation->rd_nblocks = smgrnblocks(DEFAULT_SMGR, relation); relation->rd_nblocks = smgrnblocks(DEFAULT_SMGR, relation);
return relation->rd_nblocks; return relation->rd_nblocks;
} }
/* /* ---------------------------------------------------------------------
* drop_relfilenode_buffers -- common functionality for * DropRelationBuffers
* DropRelationBuffers and
* DropRelFileNodeBuffers
* *
* XXX currently it sequentially searches the buffer pool, should be * This function removes all the buffered pages for a relation
* changed to more clever ways of searching. * from the buffer pool. Dirty pages are simply dropped, without
* bothering to write them out first. This is NOT rollback-able,
* and so should be used only with extreme caution!
*
* We assume that the caller holds an exclusive lock on the relation,
* which should assure that no new buffers will be acquired for the rel
* meanwhile.
* --------------------------------------------------------------------
*/ */
static void void
drop_relfilenode_buffers(RelFileNode rnode, bool do_local, bool do_both) DropRelationBuffers(Relation rel)
{
DropRelFileNodeBuffers(rel->rd_node, rel->rd_istemp);
}
/* ---------------------------------------------------------------------
* DropRelFileNodeBuffers
*
* This is the same as DropRelationBuffers, except that the target
* relation is specified by RelFileNode and temp status.
*
* This is NOT rollback-able. One legitimate use is to clear the
* buffer cache of buffers for a relation that is being deleted
* during transaction abort.
* --------------------------------------------------------------------
*/
void
DropRelFileNodeBuffers(RelFileNode rnode, bool istemp)
{ {
int i; int i;
BufferDesc *bufHdr; BufferDesc *bufHdr;
if (do_local) if (istemp)
{ {
for (i = 0; i < NLocBuffer; i++) for (i = 0; i < NLocBuffer; i++)
{ {
...@@ -1128,8 +1110,7 @@ drop_relfilenode_buffers(RelFileNode rnode, bool do_local, bool do_both) ...@@ -1128,8 +1110,7 @@ drop_relfilenode_buffers(RelFileNode rnode, bool do_local, bool do_both)
bufHdr->tag.rnode.relNode = InvalidOid; bufHdr->tag.rnode.relNode = InvalidOid;
} }
} }
if (!do_both) return;
return;
} }
LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
...@@ -1160,18 +1141,19 @@ recheck: ...@@ -1160,18 +1141,19 @@ recheck:
bufHdr->cntxDirty = false; bufHdr->cntxDirty = false;
/* /*
* Release any refcount we may have. * Release any refcount we may have. If someone else has a
* * pin on the buffer, we got trouble.
* This is very probably dead code, and if it isn't then it's
* probably wrong. I added the Assert to find out --- tgl
* 11/99.
*/ */
if (!(bufHdr->flags & BM_FREE)) if (!(bufHdr->flags & BM_FREE))
{ {
/* Assert checks that buffer will actually get freed! */ /* the sole pin should be ours */
Assert(PrivateRefCount[i - 1] == 1 && if (bufHdr->refcount != 1 || PrivateRefCount[i - 1] == 0)
bufHdr->refcount == 1); elog(FATAL, "DropRelFileNodeBuffers: block %u is referenced (private %ld, global %d)",
ReleaseBufferWithBufferLock(i); bufHdr->tag.blockNum,
PrivateRefCount[i - 1], bufHdr->refcount);
/* Make sure it will be released */
PrivateRefCount[i - 1] = 1;
UnpinBuffer(bufHdr);
} }
/* /*
...@@ -1184,43 +1166,6 @@ recheck: ...@@ -1184,43 +1166,6 @@ recheck:
LWLockRelease(BufMgrLock); LWLockRelease(BufMgrLock);
} }
/* ---------------------------------------------------------------------
* DropRelationBuffers
*
* This function removes all the buffered pages for a relation
* from the buffer pool. Dirty pages are simply dropped, without
* bothering to write them out first. This is NOT rollback-able,
* and so should be used only with extreme caution!
*
* We assume that the caller holds an exclusive lock on the relation,
* which should assure that no new buffers will be acquired for the rel
* meanwhile.
* --------------------------------------------------------------------
*/
void
DropRelationBuffers(Relation rel)
{
drop_relfilenode_buffers(rel->rd_node, rel->rd_myxactonly, false);
}
/* ---------------------------------------------------------------------
* DropRelFileNodeBuffers
*
* This is the same as DropRelationBuffers, except that the target
* relation is specified by RelFileNode.
*
* This is NOT rollback-able. One legitimate use is to clear the
* buffer cache of buffers for a relation that is being deleted
* during transaction abort.
* --------------------------------------------------------------------
*/
void
DropRelFileNodeBuffers(RelFileNode rnode)
{
/* We have to search both local and shared buffers... */
drop_relfilenode_buffers(rnode, true, true);
}
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* DropBuffers * DropBuffers
* *
...@@ -1296,7 +1241,7 @@ recheck: ...@@ -1296,7 +1241,7 @@ recheck:
*/ */
#ifdef NOT_USED #ifdef NOT_USED
void void
PrintBufferDescs() PrintBufferDescs(void)
{ {
int i; int i;
BufferDesc *buf = BufferDescriptors; BufferDesc *buf = BufferDescriptors;
...@@ -1331,7 +1276,7 @@ blockNum=%u, flags=0x%x, refcount=%d %ld)", ...@@ -1331,7 +1276,7 @@ blockNum=%u, flags=0x%x, refcount=%d %ld)",
#ifdef NOT_USED #ifdef NOT_USED
void void
PrintPinnedBufs() PrintPinnedBufs(void)
{ {
int i; int i;
BufferDesc *buf = BufferDescriptors; BufferDesc *buf = BufferDescriptors;
...@@ -1351,33 +1296,6 @@ blockNum=%u, flags=0x%x, refcount=%d %ld)", ...@@ -1351,33 +1296,6 @@ blockNum=%u, flags=0x%x, refcount=%d %ld)",
} }
#endif #endif
/*
* BufferPoolBlowaway
*
* this routine is solely for the purpose of experiments -- sometimes
* you may want to blowaway whatever is left from the past in buffer
* pool and start measuring some performance with a clean empty buffer
* pool.
*/
#ifdef NOT_USED
void
BufferPoolBlowaway()
{
int i;
BufferSync();
for (i = 1; i <= NBuffers; i++)
{
if (BufferIsValid(i))
{
while (BufferIsValid(i))
ReleaseBuffer(i);
}
BufTableDelete(&BufferDescriptors[i - 1]);
}
}
#endif
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* FlushRelationBuffers * FlushRelationBuffers
* *
...@@ -1428,7 +1346,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) ...@@ -1428,7 +1346,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
XLogRecPtr recptr; XLogRecPtr recptr;
int status; int status;
if (rel->rd_myxactonly) if (rel->rd_istemp)
{ {
for (i = 0; i < NLocBuffer; i++) for (i = 0; i < NLocBuffer; i++)
{ {
...@@ -1544,12 +1462,14 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock) ...@@ -1544,12 +1462,14 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
return 0; return 0;
} }
#undef ReleaseBuffer
/* /*
* release_buffer -- common functionality for * ReleaseBuffer -- remove the pin on a buffer without
* ReleaseBuffer and ReleaseBufferWithBufferLock * marking it dirty.
*/ */
static int int
release_buffer(Buffer buffer, bool havelock) ReleaseBuffer(Buffer buffer)
{ {
BufferDesc *bufHdr; BufferDesc *bufHdr;
...@@ -1570,41 +1490,14 @@ release_buffer(Buffer buffer, bool havelock) ...@@ -1570,41 +1490,14 @@ release_buffer(Buffer buffer, bool havelock)
PrivateRefCount[buffer - 1]--; PrivateRefCount[buffer - 1]--;
else else
{ {
if (!havelock) LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
UnpinBuffer(bufHdr); UnpinBuffer(bufHdr);
LWLockRelease(BufMgrLock);
if (!havelock)
LWLockRelease(BufMgrLock);
} }
return STATUS_OK; return STATUS_OK;
} }
#undef ReleaseBuffer
/*
* ReleaseBuffer -- remove the pin on a buffer without
* marking it dirty.
*/
int
ReleaseBuffer(Buffer buffer)
{
return release_buffer(buffer, false);
}
/*
* ReleaseBufferWithBufferLock
* Same as ReleaseBuffer except we hold the bufmgr lock
*/
static int
ReleaseBufferWithBufferLock(Buffer buffer)
{
return release_buffer(buffer, true);
}
#ifdef NOT_USED #ifdef NOT_USED
void void
IncrBufferRefCount_Debug(char *file, int line, Buffer buffer) IncrBufferRefCount_Debug(char *file, int line, Buffer buffer)
...@@ -1847,10 +1740,13 @@ SetBufferCommitInfoNeedsSave(Buffer buffer) ...@@ -1847,10 +1740,13 @@ SetBufferCommitInfoNeedsSave(Buffer buffer)
BufferDesc *bufHdr; BufferDesc *bufHdr;
if (BufferIsLocal(buffer)) if (BufferIsLocal(buffer))
{
WriteLocalBuffer(buffer, false);
return; return;
}
if (BAD_BUFFER_ID(buffer)) if (BAD_BUFFER_ID(buffer))
return; elog(ERROR, "SetBufferCommitInfoNeedsSave: bad buffer %d", buffer);
bufHdr = &BufferDescriptors[buffer - 1]; bufHdr = &BufferDescriptors[buffer - 1];
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* localbuf.c * localbuf.c
* local buffer manager. Fast buffer manager for temporary tables * local buffer manager. Fast buffer manager for temporary tables,
* or special cases when the operation is not visible to other backends. * which never need to be WAL-logged or checkpointed, etc.
*
* When a relation is being created, the descriptor will have rd_islocal
* set to indicate that the local buffer manager should be used. During
* the same transaction the relation is being created, any inserts or
* selects from the newly created relation will use the local buffer
* pool. rd_islocal is reset at the end of a transaction (commit/abort).
* This is useful for queries like SELECT INTO TABLE and create index.
* *
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.44 2002/06/20 20:29:34 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.45 2002/08/06 02:36:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include <sys/types.h>
#include <sys/file.h>
#include <math.h>
#include <signal.h>
#include "executor/execdebug.h"
#include "storage/buf_internals.h" #include "storage/buf_internals.h"
#include "storage/bufmgr.h" #include "storage/bufmgr.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/relcache.h" #include "utils/relcache.h"
extern long int LocalBufferFlushCount;
/*#define LBDEBUG*/
/* should be a GUC parameter some day */
int NLocBuffer = 64; int NLocBuffer = 64;
BufferDesc *LocalBufferDescriptors = NULL; BufferDesc *LocalBufferDescriptors = NULL;
Block *LocalBufferBlockPointers = NULL; Block *LocalBufferBlockPointers = NULL;
long *LocalRefCount = NULL; long *LocalRefCount = NULL;
static int nextFreeLocalBuf = 0; static int nextFreeLocalBuf = 0;
/*#define LBDEBUG*/
/* /*
* LocalBufferAlloc - * LocalBufferAlloc -
...@@ -61,11 +50,11 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr) ...@@ -61,11 +50,11 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
reln->rd_node.relNode && reln->rd_node.relNode &&
LocalBufferDescriptors[i].tag.blockNum == blockNum) LocalBufferDescriptors[i].tag.blockNum == blockNum)
{ {
#ifdef LBDEBUG #ifdef LBDEBUG
fprintf(stderr, "LB ALLOC (%u,%d) %d\n", fprintf(stderr, "LB ALLOC (%u,%d) %d\n",
RelationGetRelid(reln), blockNum, -i - 1); RelationGetRelid(reln), blockNum, -i - 1);
#endif #endif
LocalRefCount[i]++; LocalRefCount[i]++;
*foundPtr = TRUE; *foundPtr = TRUE;
return &LocalBufferDescriptors[i]; return &LocalBufferDescriptors[i];
...@@ -94,14 +83,17 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr) ...@@ -94,14 +83,17 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
elog(ERROR, "no empty local buffer."); elog(ERROR, "no empty local buffer.");
/* /*
* this buffer is not referenced but it might still be dirty (the last * this buffer is not referenced but it might still be dirty.
* transaction to touch it doesn't need its contents but has not * if that's the case, write it out before reusing it!
* flushed it). if that's the case, write it out before reusing it!
*/ */
if (bufHdr->flags & BM_DIRTY || bufHdr->cntxDirty) if (bufHdr->flags & BM_DIRTY || bufHdr->cntxDirty)
{ {
Relation bufrel = RelationNodeCacheGetRelation(bufHdr->tag.rnode); Relation bufrel = RelationNodeCacheGetRelation(bufHdr->tag.rnode);
/*
* The relcache is not supposed to throw away temp rels, so this
* should always succeed.
*/
Assert(bufrel != NULL); Assert(bufrel != NULL);
/* flush this page */ /* flush this page */
...@@ -113,26 +105,19 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr) ...@@ -113,26 +105,19 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
RelationDecrementReferenceCount(bufrel); RelationDecrementReferenceCount(bufrel);
} }
/*
* it's all ours now.
*
* We need not in tblNode currently but will in future I think, when
* we'll give up rel->rd_fd to fmgr cache.
*/
bufHdr->tag.rnode = reln->rd_node;
bufHdr->tag.blockNum = blockNum;
bufHdr->flags &= ~BM_DIRTY;
bufHdr->cntxDirty = false;
/* /*
* lazy memory allocation: allocate space on first use of a buffer. * lazy memory allocation: allocate space on first use of a buffer.
*
* Note this path cannot be taken for a buffer that was previously
* in use, so it's okay to do it (and possibly error out) before
* marking the buffer as valid.
*/ */
if (bufHdr->data == (SHMEM_OFFSET) 0) if (bufHdr->data == (SHMEM_OFFSET) 0)
{ {
char *data = (char *) malloc(BLCKSZ); char *data = (char *) malloc(BLCKSZ);
if (data == NULL) if (data == NULL)
elog(FATAL, "Out of memory in LocalBufferAlloc"); elog(ERROR, "Out of memory in LocalBufferAlloc");
/* /*
* This is a bit of a hack: bufHdr->data needs to be a shmem * This is a bit of a hack: bufHdr->data needs to be a shmem
...@@ -147,13 +132,24 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr) ...@@ -147,13 +132,24 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
LocalBufferBlockPointers[-(bufHdr->buf_id + 2)] = (Block) data; LocalBufferBlockPointers[-(bufHdr->buf_id + 2)] = (Block) data;
} }
/*
* it's all ours now.
*
* We need not in tblNode currently but will in future I think, when
* we'll give up rel->rd_fd to fmgr cache.
*/
bufHdr->tag.rnode = reln->rd_node;
bufHdr->tag.blockNum = blockNum;
bufHdr->flags &= ~BM_DIRTY;
bufHdr->cntxDirty = false;
*foundPtr = FALSE; *foundPtr = FALSE;
return bufHdr; return bufHdr;
} }
/* /*
* WriteLocalBuffer - * WriteLocalBuffer -
* writes out a local buffer * writes out a local buffer (actually, just marks it dirty)
*/ */
void void
WriteLocalBuffer(Buffer buffer, bool release) WriteLocalBuffer(Buffer buffer, bool release)
...@@ -180,7 +176,7 @@ WriteLocalBuffer(Buffer buffer, bool release) ...@@ -180,7 +176,7 @@ WriteLocalBuffer(Buffer buffer, bool release)
* InitLocalBuffer - * InitLocalBuffer -
* init the local buffer cache. Since most queries (esp. multi-user ones) * init the local buffer cache. Since most queries (esp. multi-user ones)
* don't involve local buffers, we delay allocating actual memory for the * don't involve local buffers, we delay allocating actual memory for the
* buffer until we need it. * buffers until we need them; just make the buffer headers here.
*/ */
void void
InitLocalBuffer(void) InitLocalBuffer(void)
...@@ -211,65 +207,30 @@ InitLocalBuffer(void) ...@@ -211,65 +207,30 @@ InitLocalBuffer(void)
} }
/* /*
* LocalBufferSync * AtEOXact_LocalBuffers - clean up at end of transaction.
*
* Flush all dirty buffers in the local buffer cache at commit time.
* Since the buffer cache is only used for keeping relations visible
* during a transaction, we will not need these buffers again.
* *
* Note that we have to *flush* local buffers because of them are not * This is just like AtEOXact_Buffers, but for local buffers.
* visible to checkpoint makers. But we can skip XLOG flush check.
*/ */
void void
LocalBufferSync(void) AtEOXact_LocalBuffers(bool isCommit)
{ {
int i; int i;
for (i = 0; i < NLocBuffer; i++) for (i = 0; i < NLocBuffer; i++)
{ {
BufferDesc *buf = &LocalBufferDescriptors[i]; if (LocalRefCount[i] != 0)
Relation bufrel;
if (buf->flags & BM_DIRTY || buf->cntxDirty)
{ {
#ifdef LBDEBUG BufferDesc *buf = &(LocalBufferDescriptors[i]);
fprintf(stderr, "LB SYNC %d\n", -i - 1);
#endif
bufrel = RelationNodeCacheGetRelation(buf->tag.rnode);
Assert(bufrel != NULL);
smgrwrite(DEFAULT_SMGR, bufrel, buf->tag.blockNum, if (isCommit)
(char *) MAKE_PTR(buf->data)); elog(WARNING,
smgrmarkdirty(DEFAULT_SMGR, bufrel, buf->tag.blockNum); "Local Buffer Leak: [%03d] (rel=%u/%u, blockNum=%u, flags=0x%x, refcount=%d %ld)",
LocalBufferFlushCount++; i,
buf->tag.rnode.tblNode, buf->tag.rnode.relNode,
buf->tag.blockNum, buf->flags,
buf->refcount, LocalRefCount[i]);
/* drop relcache refcount from RelationNodeCacheGetRelation */ LocalRefCount[i] = 0;
RelationDecrementReferenceCount(bufrel);
buf->flags &= ~BM_DIRTY;
buf->cntxDirty = false;
} }
} }
MemSet(LocalRefCount, 0, sizeof(long) * NLocBuffer);
nextFreeLocalBuf = 0;
}
void
ResetLocalBufferPool(void)
{
int i;
for (i = 0; i < NLocBuffer; i++)
{
BufferDesc *buf = &LocalBufferDescriptors[i];
buf->tag.rnode.relNode = InvalidOid;
buf->flags &= ~BM_DIRTY;
buf->cntxDirty = false;
}
MemSet(LocalRefCount, 0, sizeof(long) * NLocBuffer);
nextFreeLocalBuf = 0;
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.92 2002/06/20 20:29:34 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.93 2002/08/06 02:36:34 tgl Exp $
* *
* NOTES: * NOTES:
* *
...@@ -119,8 +119,7 @@ typedef struct vfd ...@@ -119,8 +119,7 @@ typedef struct vfd
unsigned short fdstate; /* bitflags for VFD's state */ unsigned short fdstate; /* bitflags for VFD's state */
/* these are the assigned bits in fdstate: */ /* these are the assigned bits in fdstate: */
#define FD_DIRTY (1 << 0) /* written to, but not yet fsync'd */ #define FD_TEMPORARY (1 << 0) /* should be unlinked when closed */
#define FD_TEMPORARY (1 << 1) /* should be unlinked when closed */
File nextFree; /* link to next free VFD, if in freelist */ File nextFree; /* link to next free VFD, if in freelist */
File lruMoreRecently; /* doubly linked recency-of-use list */ File lruMoreRecently; /* doubly linked recency-of-use list */
...@@ -396,15 +395,6 @@ LruDelete(File file) ...@@ -396,15 +395,6 @@ LruDelete(File file)
vfdP->seekPos = (long) lseek(vfdP->fd, 0L, SEEK_CUR); vfdP->seekPos = (long) lseek(vfdP->fd, 0L, SEEK_CUR);
Assert(vfdP->seekPos != -1L); Assert(vfdP->seekPos != -1L);
/* if we have written to the file, sync it before closing */
if (vfdP->fdstate & FD_DIRTY)
{
if (pg_fsync(vfdP->fd))
elog(LOG, "LruDelete: failed to fsync %s: %m",
vfdP->fileName);
vfdP->fdstate &= ~FD_DIRTY;
}
/* close the file */ /* close the file */
if (close(vfdP->fd)) if (close(vfdP->fd))
elog(LOG, "LruDelete: failed to close %s: %m", elog(LOG, "LruDelete: failed to close %s: %m",
...@@ -725,17 +715,8 @@ fileNameOpenFile(FileName fileName, ...@@ -725,17 +715,8 @@ fileNameOpenFile(FileName fileName,
/* Saved flags are adjusted to be OK for re-opening file */ /* Saved flags are adjusted to be OK for re-opening file */
vfdP->fileFlags = fileFlags & ~(O_CREAT | O_TRUNC | O_EXCL); vfdP->fileFlags = fileFlags & ~(O_CREAT | O_TRUNC | O_EXCL);
vfdP->fileMode = fileMode; vfdP->fileMode = fileMode;
vfdP->seekPos = 0; vfdP->seekPos = 0;
vfdP->fdstate = 0x0;
/*
* Have to fsync file on commit. Alternative way - log file creation
* and fsync log before actual file creation.
*/
if (fileFlags & O_CREAT)
vfdP->fdstate = FD_DIRTY;
else
vfdP->fdstate = 0x0;
return file; return file;
} }
...@@ -841,15 +822,6 @@ FileClose(File file) ...@@ -841,15 +822,6 @@ FileClose(File file)
/* remove the file from the lru ring */ /* remove the file from the lru ring */
Delete(file); Delete(file);
/* if we did any writes, sync the file before closing */
if (vfdP->fdstate & FD_DIRTY)
{
if (pg_fsync(vfdP->fd))
elog(LOG, "FileClose: failed to fsync %s: %m",
vfdP->fileName);
vfdP->fdstate &= ~FD_DIRTY;
}
/* close the file */ /* close the file */
if (close(vfdP->fd)) if (close(vfdP->fd))
elog(LOG, "FileClose: failed to close %s: %m", elog(LOG, "FileClose: failed to close %s: %m",
...@@ -1022,108 +994,11 @@ FileTruncate(File file, long offset) ...@@ -1022,108 +994,11 @@ FileTruncate(File file, long offset)
DO_DB(elog(LOG, "FileTruncate %d (%s)", DO_DB(elog(LOG, "FileTruncate %d (%s)",
file, VfdCache[file].fileName)); file, VfdCache[file].fileName));
FileSync(file);
FileAccess(file); FileAccess(file);
returnCode = ftruncate(VfdCache[file].fd, (size_t) offset); returnCode = ftruncate(VfdCache[file].fd, (size_t) offset);
return returnCode; return returnCode;
} }
/*
* FileSync --- if a file is marked as dirty, fsync it.
*
* The FD_DIRTY bit is slightly misnamed: it doesn't mean that we need to
* write the file, but that we *have* written it and need to execute an
* fsync() to ensure the changes are down on disk before we mark the current
* transaction committed.
*
* FD_DIRTY is set by FileWrite or by an explicit FileMarkDirty() call.
* It is cleared after successfully fsync'ing the file. FileClose() will
* fsync a dirty File that is about to be closed, since there will be no
* other place to remember the need to fsync after the VFD is gone.
*
* Note that the DIRTY bit is logically associated with the actual disk file,
* not with any particular kernel FD we might have open for it. We assume
* that fsync will force out any dirty buffers for that file, whether or not
* they were written through the FD being used for the fsync call --- they
* might even have been written by some other backend!
*
* Note also that LruDelete currently fsyncs a dirty file that it is about
* to close the kernel file descriptor for. The idea there is to avoid
* having to re-open the kernel descriptor later. But it's not real clear
* that this is a performance win; we could end up fsyncing the same file
* multiple times in a transaction, which would probably cost more time
* than is saved by avoiding an open() call. This should be studied.
*
* This routine used to think it could skip the fsync if the file is
* physically closed, but that is now WRONG; see comments for FileMarkDirty.
*/
int
FileSync(File file)
{
int returnCode;
Assert(FileIsValid(file));
if (!(VfdCache[file].fdstate & FD_DIRTY))
{
/* Need not sync if file is not dirty. */
returnCode = 0;
}
else if (!enableFsync)
{
/* Don't force the file open if pg_fsync isn't gonna sync it. */
returnCode = 0;
VfdCache[file].fdstate &= ~FD_DIRTY;
}
else
{
/*
* We don't use FileAccess() because we don't want to force the
* file to the front of the LRU ring; we aren't expecting to
* access it again soon.
*/
if (FileIsNotOpen(file))
{
returnCode = LruInsert(file);
if (returnCode != 0)
return returnCode;
}
returnCode = pg_fsync(VfdCache[file].fd);
if (returnCode == 0)
VfdCache[file].fdstate &= ~FD_DIRTY;
}
return returnCode;
}
/*
* FileMarkDirty --- mark a file as needing fsync at transaction commit.
*
* Since FileWrite marks the file dirty, this routine is not needed in
* normal use. It is called when the buffer manager detects that some other
* backend has written out a shared buffer that this backend dirtied (but
* didn't write) in the current xact. In that scenario, we need to fsync
* the file before we can commit. We cannot assume that the other backend
* has fsync'd the file yet; we need to do our own fsync to ensure that
* (a) the disk page is written and (b) this backend's commit is delayed
* until the write is complete.
*
* Note we are assuming that an fsync issued by this backend will write
* kernel disk buffers that were dirtied by another backend. Furthermore,
* it doesn't matter whether we currently have the file physically open;
* we must fsync even if we have to re-open the file to do it.
*/
void
FileMarkDirty(File file)
{
Assert(FileIsValid(file));
DO_DB(elog(LOG, "FileMarkDirty: %d (%s)",
file, VfdCache[file].fileName));
VfdCache[file].fdstate |= FD_DIRTY;
}
/* /*
* Routines that want to use stdio (ie, FILE*) should use AllocateFile * Routines that want to use stdio (ie, FILE*) should use AllocateFile
...@@ -1142,7 +1017,6 @@ FileMarkDirty(File file) ...@@ -1142,7 +1017,6 @@ FileMarkDirty(File file)
* *
* Ideally this should be the *only* direct call of fopen() in the backend. * Ideally this should be the *only* direct call of fopen() in the backend.
*/ */
FILE * FILE *
AllocateFile(char *name, char *mode) AllocateFile(char *name, char *mode)
{ {
...@@ -1229,12 +1103,6 @@ closeAllVfds(void) ...@@ -1229,12 +1103,6 @@ closeAllVfds(void)
* exit (it doesn't particularly care which). All still-open temporary-file * exit (it doesn't particularly care which). All still-open temporary-file
* VFDs are closed, which also causes the underlying files to be deleted. * VFDs are closed, which also causes the underlying files to be deleted.
* Furthermore, all "allocated" stdio files are closed. * Furthermore, all "allocated" stdio files are closed.
*
* This routine is not involved in fsync'ing non-temporary files at xact
* commit; that is done by FileSync under control of the buffer manager.
* During a commit, that is done *before* control gets here. If we still
* have any needs-fsync bits set when we get here, we assume this is abort
* and clear them.
*/ */
void void
AtEOXact_Files(void) AtEOXact_Files(void)
...@@ -1249,8 +1117,6 @@ AtEOXact_Files(void) ...@@ -1249,8 +1117,6 @@ AtEOXact_Files(void)
if ((VfdCache[i].fdstate & FD_TEMPORARY) && if ((VfdCache[i].fdstate & FD_TEMPORARY) &&
VfdCache[i].fileName != NULL) VfdCache[i].fileName != NULL)
FileClose(i); FileClose(i);
else
VfdCache[i].fdstate &= ~FD_DIRTY;
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.91 2002/06/20 20:29:35 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.92 2002/08/06 02:36:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -381,16 +381,7 @@ mdclose_fd(int fd) ...@@ -381,16 +381,7 @@ mdclose_fd(int fd)
/* if not closed already */ /* if not closed already */
if (v->mdfd_vfd >= 0) if (v->mdfd_vfd >= 0)
{
/*
* We sync the file descriptor so that we don't need to reopen
* it at transaction commit to force changes to disk. (This
* is not really optional, because we are about to forget that
* the file even exists...)
*/
FileSync(v->mdfd_vfd);
FileClose(v->mdfd_vfd); FileClose(v->mdfd_vfd);
}
/* Now free vector */ /* Now free vector */
v = v->mdfd_chain; v = v->mdfd_chain;
if (ov != &Md_fdvec[fd]) if (ov != &Md_fdvec[fd])
...@@ -403,16 +394,7 @@ mdclose_fd(int fd) ...@@ -403,16 +394,7 @@ mdclose_fd(int fd)
if (v != (MdfdVec *) NULL) if (v != (MdfdVec *) NULL)
{ {
if (v->mdfd_vfd >= 0) if (v->mdfd_vfd >= 0)
{
/*
* We sync the file descriptor so that we don't need to reopen
* it at transaction commit to force changes to disk. (This
* is not really optional, because we are about to forget that
* the file even exists...)
*/
FileSync(v->mdfd_vfd);
FileClose(v->mdfd_vfd); FileClose(v->mdfd_vfd);
}
} }
#endif #endif
...@@ -497,56 +479,16 @@ mdwrite(Relation reln, BlockNumber blocknum, char *buffer) ...@@ -497,56 +479,16 @@ mdwrite(Relation reln, BlockNumber blocknum, char *buffer)
return SM_SUCCESS; return SM_SUCCESS;
} }
/*
* mdflush() -- Synchronously write a block to disk.
*
* This is exactly like mdwrite(), but doesn't return until the file
* system buffer cache has been flushed.
*/
int
mdflush(Relation reln, BlockNumber blocknum, char *buffer)
{
int status;
long seekpos;
MdfdVec *v;
v = _mdfd_getseg(reln, blocknum);
#ifndef LET_OS_MANAGE_FILESIZE
seekpos = (long) (BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE)));
#ifdef DIAGNOSTIC
if (seekpos >= BLCKSZ * RELSEG_SIZE)
elog(FATAL, "seekpos too big!");
#endif
#else
seekpos = (long) (BLCKSZ * (blocknum));
#endif
if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
return SM_FAIL;
/* write and sync the block */
status = SM_SUCCESS;
if (FileWrite(v->mdfd_vfd, buffer, BLCKSZ) != BLCKSZ
|| FileSync(v->mdfd_vfd) < 0)
status = SM_FAIL;
return status;
}
/* /*
* mdblindwrt() -- Write a block to disk blind. * mdblindwrt() -- Write a block to disk blind.
* *
* We have to be able to do this using only the name and OID of * We have to be able to do this using only the rnode of the relation
* the database and relation in which the block belongs. Otherwise * in which the block belongs. Otherwise this is much like mdwrite().
* this is much like mdwrite(). If dofsync is TRUE, then we fsync
* the file, making it more like mdflush().
*/ */
int int
mdblindwrt(RelFileNode rnode, mdblindwrt(RelFileNode rnode,
BlockNumber blkno, BlockNumber blkno,
char *buffer, char *buffer)
bool dofsync)
{ {
int status; int status;
long seekpos; long seekpos;
...@@ -568,7 +510,6 @@ mdblindwrt(RelFileNode rnode, ...@@ -568,7 +510,6 @@ mdblindwrt(RelFileNode rnode,
#endif #endif
errno = 0; errno = 0;
if (lseek(fd, seekpos, SEEK_SET) != seekpos) if (lseek(fd, seekpos, SEEK_SET) != seekpos)
{ {
elog(LOG, "mdblindwrt: lseek(%ld) failed: %m", seekpos); elog(LOG, "mdblindwrt: lseek(%ld) failed: %m", seekpos);
...@@ -578,7 +519,7 @@ mdblindwrt(RelFileNode rnode, ...@@ -578,7 +519,7 @@ mdblindwrt(RelFileNode rnode,
status = SM_SUCCESS; status = SM_SUCCESS;
/* write and optionally sync the block */ /* write the block */
errno = 0; errno = 0;
if (write(fd, buffer, BLCKSZ) != BLCKSZ) if (write(fd, buffer, BLCKSZ) != BLCKSZ)
{ {
...@@ -598,54 +539,6 @@ mdblindwrt(RelFileNode rnode, ...@@ -598,54 +539,6 @@ mdblindwrt(RelFileNode rnode,
return status; return status;
} }
/*
* mdmarkdirty() -- Mark the specified block "dirty" (ie, needs fsync).
*
* Returns SM_SUCCESS or SM_FAIL.
*/
int
mdmarkdirty(Relation reln, BlockNumber blkno)
{
MdfdVec *v;
v = _mdfd_getseg(reln, blkno);
FileMarkDirty(v->mdfd_vfd);
return SM_SUCCESS;
}
/*
* mdblindmarkdirty() -- Mark the specified block "dirty" (ie, needs fsync).
*
* We have to be able to do this using only the name and OID of
* the database and relation in which the block belongs. Otherwise
* this is much like mdmarkdirty(). However, we do the fsync immediately
* rather than building md/fd datastructures to postpone it till later.
*/
int
mdblindmarkdirty(RelFileNode rnode,
BlockNumber blkno)
{
int status;
int fd;
fd = _mdfd_blind_getseg(rnode, blkno);
if (fd < 0)
return SM_FAIL;
status = SM_SUCCESS;
if (pg_fsync(fd) < 0)
status = SM_FAIL;
if (close(fd) < 0)
status = SM_FAIL;
return status;
}
/* /*
* mdnblocks() -- Get the number of blocks stored in a relation. * mdnblocks() -- Get the number of blocks stored in a relation.
* *
...@@ -796,61 +689,36 @@ mdtruncate(Relation reln, BlockNumber nblocks) ...@@ -796,61 +689,36 @@ mdtruncate(Relation reln, BlockNumber nblocks)
/* /*
* mdcommit() -- Commit a transaction. * mdcommit() -- Commit a transaction.
* *
* All changes to magnetic disk relations must be forced to stable
* storage. This routine makes a pass over the private table of
* file descriptors. Any descriptors to which we have done writes,
* but not synced, are synced here.
*
* Returns SM_SUCCESS or SM_FAIL with errno set as appropriate. * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
*/ */
int int
mdcommit() mdcommit(void)
{ {
int i; /*
MdfdVec *v; * We don't actually have to do anything here...
*/
for (i = 0; i < CurFd; i++)
{
v = &Md_fdvec[i];
if (v->mdfd_flags & MDFD_FREE)
continue;
/* Sync the file entry */
#ifndef LET_OS_MANAGE_FILESIZE
for (; v != (MdfdVec *) NULL; v = v->mdfd_chain)
#else
if (v != (MdfdVec *) NULL)
#endif
{
if (FileSync(v->mdfd_vfd) < 0)
return SM_FAIL;
}
}
return SM_SUCCESS; return SM_SUCCESS;
} }
/* /*
* mdabort() -- Abort a transaction. * mdabort() -- Abort a transaction.
* *
* Changes need not be forced to disk at transaction abort. We mark * Changes need not be forced to disk at transaction abort.
* all file descriptors as clean here. Always returns SM_SUCCESS.
*/ */
int int
mdabort() mdabort(void)
{ {
/* /*
* We don't actually have to do anything here. fd.c will discard * We don't actually have to do anything here...
* fsync-needed bits in its AtEOXact_Files() routine.
*/ */
return SM_SUCCESS; return SM_SUCCESS;
} }
/* /*
* mdsync() -- Sync storage. * mdsync() -- Sync previous writes to stable storage.
*
*/ */
int int
mdsync() mdsync(void)
{ {
sync(); sync();
if (IsUnderPostmaster) if (IsUnderPostmaster)
...@@ -861,11 +729,9 @@ mdsync() ...@@ -861,11 +729,9 @@ mdsync()
/* /*
* _fdvec_alloc () -- grab a free (or new) md file descriptor vector. * _fdvec_alloc () -- grab a free (or new) md file descriptor vector.
*
*/ */
static static int
int _fdvec_alloc(void)
_fdvec_alloc()
{ {
MdfdVec *nvec; MdfdVec *nvec;
int fdvec, int fdvec,
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/Attic/mm.c,v 1.31 2002/06/20 20:29:36 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/Attic/mm.c,v 1.32 2002/08/06 02:36:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -81,7 +81,7 @@ static HTAB *MMCacheHT; ...@@ -81,7 +81,7 @@ static HTAB *MMCacheHT;
static HTAB *MMRelCacheHT; static HTAB *MMRelCacheHT;
int int
mminit() mminit(void)
{ {
char *mmcacheblk; char *mmcacheblk;
int mmsize = 0; int mmsize = 0;
...@@ -151,7 +151,7 @@ mminit() ...@@ -151,7 +151,7 @@ mminit()
} }
int int
mmshutdown() mmshutdown(void)
{ {
return SM_SUCCESS; return SM_SUCCESS;
} }
...@@ -442,31 +442,16 @@ mmwrite(Relation reln, BlockNumber blocknum, char *buffer) ...@@ -442,31 +442,16 @@ mmwrite(Relation reln, BlockNumber blocknum, char *buffer)
return SM_SUCCESS; return SM_SUCCESS;
} }
/*
* mmflush() -- Synchronously write a block to stable storage.
*
* For main-memory relations, this is exactly equivalent to mmwrite().
*/
int
mmflush(Relation reln, BlockNumber blocknum, char *buffer)
{
return mmwrite(reln, blocknum, buffer);
}
/* /*
* mmblindwrt() -- Write a block to stable storage blind. * mmblindwrt() -- Write a block to stable storage blind.
* *
* We have to be able to do this using only the name and OID of * We have to be able to do this using only the rnode of the relation
* the database and relation in which the block belongs. * in which the block belongs. Otherwise this is much like mmwrite().
*/ */
int int
mmblindwrt(char *dbstr, mmblindwrt(RelFileNode rnode,
char *relstr,
Oid dbid,
Oid relid,
BlockNumber blkno, BlockNumber blkno,
char *buffer, char *buffer)
bool dofsync)
{ {
return SM_FAIL; return SM_FAIL;
} }
...@@ -512,7 +497,7 @@ mmnblocks(Relation reln) ...@@ -512,7 +497,7 @@ mmnblocks(Relation reln)
* Returns SM_SUCCESS or SM_FAIL with errno set as appropriate. * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
*/ */
int int
mmcommit() mmcommit(void)
{ {
return SM_SUCCESS; return SM_SUCCESS;
} }
...@@ -522,7 +507,7 @@ mmcommit() ...@@ -522,7 +507,7 @@ mmcommit()
*/ */
int int
mmabort() mmabort(void)
{ {
return SM_SUCCESS; return SM_SUCCESS;
} }
...@@ -536,7 +521,7 @@ mmabort() ...@@ -536,7 +521,7 @@ mmabort()
* manager will use. * manager will use.
*/ */
int int
MMShmemSize() MMShmemSize(void)
{ {
int size = 0; int size = 0;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.57 2002/06/20 20:29:36 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.58 2002/08/06 02:36:34 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -40,12 +40,8 @@ typedef struct f_smgr ...@@ -40,12 +40,8 @@ typedef struct f_smgr
char *buffer); char *buffer);
int (*smgr_write) (Relation reln, BlockNumber blocknum, int (*smgr_write) (Relation reln, BlockNumber blocknum,
char *buffer); char *buffer);
int (*smgr_flush) (Relation reln, BlockNumber blocknum,
char *buffer);
int (*smgr_blindwrt) (RelFileNode rnode, BlockNumber blkno, int (*smgr_blindwrt) (RelFileNode rnode, BlockNumber blkno,
char *buffer, bool dofsync); char *buffer);
int (*smgr_markdirty) (Relation reln, BlockNumber blkno);
int (*smgr_blindmarkdirty) (RelFileNode, BlockNumber blkno);
BlockNumber (*smgr_nblocks) (Relation reln); BlockNumber (*smgr_nblocks) (Relation reln);
BlockNumber (*smgr_truncate) (Relation reln, BlockNumber nblocks); BlockNumber (*smgr_truncate) (Relation reln, BlockNumber nblocks);
int (*smgr_commit) (void); /* may be NULL */ int (*smgr_commit) (void); /* may be NULL */
...@@ -62,15 +58,15 @@ static f_smgr smgrsw[] = { ...@@ -62,15 +58,15 @@ static f_smgr smgrsw[] = {
/* magnetic disk */ /* magnetic disk */
{mdinit, NULL, mdcreate, mdunlink, mdextend, mdopen, mdclose, {mdinit, NULL, mdcreate, mdunlink, mdextend, mdopen, mdclose,
mdread, mdwrite, mdflush, mdblindwrt, mdmarkdirty, mdblindmarkdirty, mdread, mdwrite, mdblindwrt,
mdnblocks, mdtruncate, mdcommit, mdabort, mdsync mdnblocks, mdtruncate, mdcommit, mdabort, mdsync
}, },
#ifdef STABLE_MEMORY_STORAGE #ifdef STABLE_MEMORY_STORAGE
/* main memory */ /* main memory */
{mminit, mmshutdown, mmcreate, mmunlink, mmextend, mmopen, mmclose, {mminit, mmshutdown, mmcreate, mmunlink, mmextend, mmopen, mmclose,
mmread, mmwrite, mmflush, mmblindwrt, mmmarkdirty, mmblindmarkdirty, mmread, mmwrite, mmblindwrt,
mmnblocks, NULL, mmcommit, mmabort}, mmnblocks, NULL, mmcommit, mmabort, NULL},
#endif #endif
}; };
...@@ -110,6 +106,7 @@ typedef struct PendingRelDelete ...@@ -110,6 +106,7 @@ typedef struct PendingRelDelete
{ {
RelFileNode relnode; /* relation that may need to be deleted */ RelFileNode relnode; /* relation that may need to be deleted */
int16 which; /* which storage manager? */ int16 which; /* which storage manager? */
bool isTemp; /* is it a temporary relation? */
bool atCommit; /* T=delete at commit; F=delete at abort */ bool atCommit; /* T=delete at commit; F=delete at abort */
struct PendingRelDelete *next; /* linked-list link */ struct PendingRelDelete *next; /* linked-list link */
} PendingRelDelete; } PendingRelDelete;
...@@ -123,7 +120,7 @@ static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */ ...@@ -123,7 +120,7 @@ static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
* *
*/ */
int int
smgrinit() smgrinit(void)
{ {
int i; int i;
...@@ -181,6 +178,7 @@ smgrcreate(int16 which, Relation reln) ...@@ -181,6 +178,7 @@ smgrcreate(int16 which, Relation reln)
MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete)); MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
pending->relnode = reln->rd_node; pending->relnode = reln->rd_node;
pending->which = which; pending->which = which;
pending->isTemp = reln->rd_istemp;
pending->atCommit = false; /* delete if abort */ pending->atCommit = false; /* delete if abort */
pending->next = pendingDeletes; pending->next = pendingDeletes;
pendingDeletes = pending; pendingDeletes = pending;
...@@ -208,6 +206,7 @@ smgrunlink(int16 which, Relation reln) ...@@ -208,6 +206,7 @@ smgrunlink(int16 which, Relation reln)
MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete)); MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
pending->relnode = reln->rd_node; pending->relnode = reln->rd_node;
pending->which = which; pending->which = which;
pending->isTemp = reln->rd_istemp;
pending->atCommit = true; /* delete if commit */ pending->atCommit = true; /* delete if commit */
pending->next = pendingDeletes; pending->next = pendingDeletes;
pendingDeletes = pending; pendingDeletes = pending;
...@@ -312,8 +311,10 @@ smgrread(int16 which, Relation reln, BlockNumber blocknum, char *buffer) ...@@ -312,8 +311,10 @@ smgrread(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
/* /*
* smgrwrite() -- Write the supplied buffer out. * smgrwrite() -- Write the supplied buffer out.
* *
* This is not a synchronous write -- the interface for that is * This is not a synchronous write -- the block is not necessarily
* smgrflush(). The buffer is written out via the appropriate * on disk at return, only dumped out to the kernel.
*
* The buffer is written out via the appropriate
* storage manager. This routine returns SM_SUCCESS or aborts * storage manager. This routine returns SM_SUCCESS or aborts
* the current transaction. * the current transaction.
*/ */
...@@ -331,23 +332,6 @@ smgrwrite(int16 which, Relation reln, BlockNumber blocknum, char *buffer) ...@@ -331,23 +332,6 @@ smgrwrite(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
return status; return status;
} }
/*
* smgrflush() -- A synchronous smgrwrite().
*/
int
smgrflush(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
{
int status;
status = (*(smgrsw[which].smgr_flush)) (reln, blocknum, buffer);
if (status == SM_FAIL)
elog(ERROR, "cannot flush block %d of %s to stable store: %m",
blocknum, RelationGetRelationName(reln));
return status;
}
/* /*
* smgrblindwrt() -- Write a page out blind. * smgrblindwrt() -- Write a page out blind.
* *
...@@ -357,20 +341,18 @@ smgrflush(int16 which, Relation reln, BlockNumber blocknum, char *buffer) ...@@ -357,20 +341,18 @@ smgrflush(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
* that has not yet committed, which created a new relation. In * that has not yet committed, which created a new relation. In
* this case, the buffer manager will call smgrblindwrt() with * this case, the buffer manager will call smgrblindwrt() with
* the name and OID of the database and the relation to which the * the name and OID of the database and the relation to which the
* buffer belongs. Every storage manager must be able to force * buffer belongs. Every storage manager must be able to write
* this page down to stable storage in this circumstance. The * this page out to stable storage in this circumstance.
* write should be synchronous if dofsync is true.
*/ */
int int
smgrblindwrt(int16 which, smgrblindwrt(int16 which,
RelFileNode rnode, RelFileNode rnode,
BlockNumber blkno, BlockNumber blkno,
char *buffer, char *buffer)
bool dofsync)
{ {
int status; int status;
status = (*(smgrsw[which].smgr_blindwrt)) (rnode, blkno, buffer, dofsync); status = (*(smgrsw[which].smgr_blindwrt)) (rnode, blkno, buffer);
if (status == SM_FAIL) if (status == SM_FAIL)
elog(ERROR, "cannot write block %d of %u/%u blind: %m", elog(ERROR, "cannot write block %d of %u/%u blind: %m",
...@@ -379,53 +361,6 @@ smgrblindwrt(int16 which, ...@@ -379,53 +361,6 @@ smgrblindwrt(int16 which,
return status; return status;
} }
/*
* smgrmarkdirty() -- Mark a page dirty (needs fsync).
*
* Mark the specified page as needing to be fsync'd before commit.
* Ordinarily, the storage manager will do this implicitly during
* smgrwrite(). However, the buffer manager may discover that some
* other backend has written a buffer that we dirtied in the current
* transaction. In that case, we still need to fsync the file to be
* sure the page is down to disk before we commit.
*/
int
smgrmarkdirty(int16 which,
Relation reln,
BlockNumber blkno)
{
int status;
status = (*(smgrsw[which].smgr_markdirty)) (reln, blkno);
if (status == SM_FAIL)
elog(ERROR, "cannot mark block %d of %s: %m",
blkno, RelationGetRelationName(reln));
return status;
}
/*
* smgrblindmarkdirty() -- Mark a page dirty, "blind".
*
* Just like smgrmarkdirty, except we don't have a reldesc.
*/
int
smgrblindmarkdirty(int16 which,
RelFileNode rnode,
BlockNumber blkno)
{
int status;
status = (*(smgrsw[which].smgr_blindmarkdirty)) (rnode, blkno);
if (status == SM_FAIL)
elog(ERROR, "cannot mark block %d of %u/%u blind: %m",
blkno, rnode.tblNode, rnode.relNode);
return status;
}
/* /*
* smgrnblocks() -- Calculate the number of POSTGRES blocks in the * smgrnblocks() -- Calculate the number of POSTGRES blocks in the
* supplied relation. * supplied relation.
...@@ -504,7 +439,7 @@ smgrDoPendingDeletes(bool isCommit) ...@@ -504,7 +439,7 @@ smgrDoPendingDeletes(bool isCommit)
* any in the commit case, but there can be in the abort * any in the commit case, but there can be in the abort
* case). * case).
*/ */
DropRelFileNodeBuffers(pending->relnode); DropRelFileNodeBuffers(pending->relnode, pending->isTemp);
/* /*
* Tell the free space map to forget this relation. It won't * Tell the free space map to forget this relation. It won't
...@@ -531,11 +466,13 @@ smgrDoPendingDeletes(bool isCommit) ...@@ -531,11 +466,13 @@ smgrDoPendingDeletes(bool isCommit)
} }
/* /*
* smgrcommit(), smgrabort() -- Commit or abort changes made during the * smgrcommit() -- Prepare to commit changes made during the current
* current transaction. * transaction.
*
* This is called before we actually commit.
*/ */
int int
smgrcommit() smgrcommit(void)
{ {
int i; int i;
...@@ -553,8 +490,11 @@ smgrcommit() ...@@ -553,8 +490,11 @@ smgrcommit()
return SM_SUCCESS; return SM_SUCCESS;
} }
/*
* smgrabort() -- Abort changes made during the current transaction.
*/
int int
smgrabort() smgrabort(void)
{ {
int i; int i;
...@@ -572,8 +512,11 @@ smgrabort() ...@@ -572,8 +512,11 @@ smgrabort()
return SM_SUCCESS; return SM_SUCCESS;
} }
/*
* Sync files to disk at checkpoint time.
*/
int int
smgrsync() smgrsync(void)
{ {
int i; int i;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.170 2002/08/04 18:12:15 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.171 2002/08/06 02:36:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_amop.h" #include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h" #include "catalog/pg_amproc.h"
#include "catalog/pg_attrdef.h" #include "catalog/pg_attrdef.h"
...@@ -94,13 +95,6 @@ static HTAB *RelationSysNameCache; ...@@ -94,13 +95,6 @@ static HTAB *RelationSysNameCache;
*/ */
static HTAB *RelationNodeCache; static HTAB *RelationNodeCache;
/*
* newlyCreatedRelns -
* relations created during this transaction. We need to keep track of
* these.
*/
static List *newlyCreatedRelns = NIL;
/* /*
* This flag is false until we have prepared the critical relcache entries * This flag is false until we have prepared the critical relcache entries
* that are needed to do indexscans on the tables read by relcache building. * that are needed to do indexscans on the tables read by relcache building.
...@@ -865,9 +859,12 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo, ...@@ -865,9 +859,12 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
RelationSetReferenceCount(relation, 1); RelationSetReferenceCount(relation, 1);
/* /*
* normal relations are not nailed into the cache * normal relations are not nailed into the cache; nor can a pre-existing
* relation be new or temp.
*/ */
relation->rd_isnailed = false; relation->rd_isnailed = false;
relation->rd_isnew = false;
relation->rd_istemp = false;
/* /*
* initialize the tuple descriptor (relation->rd_att). * initialize the tuple descriptor (relation->rd_att).
...@@ -957,9 +954,6 @@ RelationInitIndexAccessInfo(Relation relation) ...@@ -957,9 +954,6 @@ RelationInitIndexAccessInfo(Relation relation)
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
relation->rd_index = iform; relation->rd_index = iform;
/* this field is now kinda redundant... */
relation->rd_uniqueindex = iform->indisunique;
/* /*
* Make a copy of the pg_am entry for the index's access method * Make a copy of the pg_am entry for the index's access method
*/ */
...@@ -1359,9 +1353,12 @@ formrdesc(const char *relationName, ...@@ -1359,9 +1353,12 @@ formrdesc(const char *relationName,
RelationSetReferenceCount(relation, 1); RelationSetReferenceCount(relation, 1);
/* /*
* all entries built with this routine are nailed-in-cache * all entries built with this routine are nailed-in-cache; none are
* for new or temp relations.
*/ */
relation->rd_isnailed = true; relation->rd_isnailed = true;
relation->rd_isnew = false;
relation->rd_istemp = false;
/* /*
* initialize relation tuple form * initialize relation tuple form
...@@ -1603,7 +1600,9 @@ RelationClose(Relation relation) ...@@ -1603,7 +1600,9 @@ RelationClose(Relation relation)
RelationDecrementReferenceCount(relation); RelationDecrementReferenceCount(relation);
#ifdef RELCACHE_FORCE_RELEASE #ifdef RELCACHE_FORCE_RELEASE
if (RelationHasReferenceCountZero(relation) && !relation->rd_myxactonly) if (RelationHasReferenceCountZero(relation) &&
!relation->rd_isnew &&
!relation->rd_istemp)
RelationClearRelation(relation, false); RelationClearRelation(relation, false);
#endif #endif
} }
...@@ -1734,13 +1733,14 @@ RelationClearRelation(Relation relation, bool rebuild) ...@@ -1734,13 +1733,14 @@ RelationClearRelation(Relation relation, bool rebuild)
{ {
/* /*
* When rebuilding an open relcache entry, must preserve ref count * When rebuilding an open relcache entry, must preserve ref count
* and myxactonly flag. Also attempt to preserve the tupledesc, * and new/temp flags. Also attempt to preserve the tupledesc,
* rewrite rules, and trigger substructures in place. Furthermore * rewrite rules, and trigger substructures in place. Furthermore
* we save/restore rd_nblocks (in case it is a local relation) * we save/restore rd_nblocks (in case it is a new/temp relation)
* *and* call RelationGetNumberOfBlocks (in case it isn't). * *and* call RelationGetNumberOfBlocks (in case it isn't).
*/ */
int old_refcnt = relation->rd_refcnt; int old_refcnt = relation->rd_refcnt;
bool old_myxactonly = relation->rd_myxactonly; bool old_isnew = relation->rd_isnew;
bool old_istemp = relation->rd_istemp;
TupleDesc old_att = relation->rd_att; TupleDesc old_att = relation->rd_att;
RuleLock *old_rules = relation->rd_rules; RuleLock *old_rules = relation->rd_rules;
MemoryContext old_rulescxt = relation->rd_rulescxt; MemoryContext old_rulescxt = relation->rd_rulescxt;
...@@ -1763,7 +1763,8 @@ RelationClearRelation(Relation relation, bool rebuild) ...@@ -1763,7 +1763,8 @@ RelationClearRelation(Relation relation, bool rebuild)
buildinfo.i.info_id); buildinfo.i.info_id);
} }
RelationSetReferenceCount(relation, old_refcnt); RelationSetReferenceCount(relation, old_refcnt);
relation->rd_myxactonly = old_myxactonly; relation->rd_isnew = old_isnew;
relation->rd_istemp = old_istemp;
if (equalTupleDescs(old_att, relation->rd_att)) if (equalTupleDescs(old_att, relation->rd_att))
{ {
FreeTupleDesc(relation->rd_att); FreeTupleDesc(relation->rd_att);
...@@ -1810,11 +1811,11 @@ RelationFlushRelation(Relation relation) ...@@ -1810,11 +1811,11 @@ RelationFlushRelation(Relation relation)
{ {
bool rebuild; bool rebuild;
if (relation->rd_myxactonly) if (relation->rd_isnew || relation->rd_istemp)
{ {
/* /*
* Local rels should always be rebuilt, not flushed; the relcache * New and temp relcache entries must always be rebuilt, not
* entry must live until RelationPurgeLocalRelation(). * flushed; else we'd forget those two important status bits.
*/ */
rebuild = true; rebuild = true;
} }
...@@ -1830,11 +1831,10 @@ RelationFlushRelation(Relation relation) ...@@ -1830,11 +1831,10 @@ RelationFlushRelation(Relation relation)
} }
/* /*
* RelationForgetRelation - * RelationForgetRelation - unconditionally remove a relcache entry
* *
* RelationClearRelation + if the relation is myxactonly then * External interface for destroying a relcache entry when we
* remove the relation descriptor from the newly created * drop the relation.
* relation list.
*/ */
void void
RelationForgetRelation(Oid rid) RelationForgetRelation(Oid rid)
...@@ -1849,31 +1849,6 @@ RelationForgetRelation(Oid rid) ...@@ -1849,31 +1849,6 @@ RelationForgetRelation(Oid rid)
if (!RelationHasReferenceCountZero(relation)) if (!RelationHasReferenceCountZero(relation))
elog(ERROR, "RelationForgetRelation: relation %u is still open", rid); elog(ERROR, "RelationForgetRelation: relation %u is still open", rid);
/* If local, remove from list */
if (relation->rd_myxactonly)
{
List *curr;
List *prev = NIL;
foreach(curr, newlyCreatedRelns)
{
Relation reln = lfirst(curr);
Assert(reln != NULL && reln->rd_myxactonly);
if (RelationGetRelid(reln) == rid)
break;
prev = curr;
}
if (curr == NIL)
elog(ERROR, "Local relation %s not found in list",
RelationGetRelationName(relation));
if (prev == NIL)
newlyCreatedRelns = lnext(newlyCreatedRelns);
else
lnext(prev) = lnext(curr);
pfree(curr);
}
/* Unconditionally destroy the relcache entry */ /* Unconditionally destroy the relcache entry */
RelationClearRelation(relation, false); RelationClearRelation(relation, false);
} }
...@@ -1909,7 +1884,7 @@ RelationIdInvalidateRelationCacheByRelationId(Oid relationId) ...@@ -1909,7 +1884,7 @@ RelationIdInvalidateRelationCacheByRelationId(Oid relationId)
* and rebuild those with positive reference counts. * and rebuild those with positive reference counts.
* *
* This is currently used only to recover from SI message buffer overflow, * This is currently used only to recover from SI message buffer overflow,
* so we do not touch transaction-local relations; they cannot be targets * so we do not touch new-in-transaction relations; they cannot be targets
* of cross-backend SI updates (and our own updates now go through a * of cross-backend SI updates (and our own updates now go through a
* separate linked list that isn't limited by the SI message buffer size). * separate linked list that isn't limited by the SI message buffer size).
* *
...@@ -1940,13 +1915,13 @@ RelationCacheInvalidate(void) ...@@ -1940,13 +1915,13 @@ RelationCacheInvalidate(void)
{ {
relation = idhentry->reldesc; relation = idhentry->reldesc;
/* Ignore xact-local relations, since they are never SI targets */ /* Ignore new relations, since they are never SI targets */
if (relation->rd_myxactonly) if (relation->rd_isnew)
continue; continue;
relcacheInvalsReceived++; relcacheInvalsReceived++;
if (RelationHasReferenceCountZero(relation)) if (RelationHasReferenceCountZero(relation) && !relation->rd_istemp)
{ {
/* Delete this entry immediately */ /* Delete this entry immediately */
RelationClearRelation(relation, false); RelationClearRelation(relation, false);
...@@ -1968,37 +1943,16 @@ RelationCacheInvalidate(void) ...@@ -1968,37 +1943,16 @@ RelationCacheInvalidate(void)
} }
/* /*
* AtEOXactRelationCache * AtEOXact_RelationCache
* *
* Clean up the relcache at transaction commit or abort. * Clean up the relcache at transaction commit or abort.
*
* During transaction abort, we must reset relcache entry ref counts
* to their normal not-in-a-transaction state. A ref count may be
* too high because some routine was exited by elog() between
* incrementing and decrementing the count.
*
* During commit, we should not have to do this, but it's useful to
* check that the counts are correct to catch missed relcache closes.
* Since that's basically a debugging thing, only pay the cost when
* assert checking is enabled.
*
* In bootstrap mode, forget the debugging checks --- the bootstrap code
* expects relations to stay open across start/commit transaction calls.
*/ */
void void
AtEOXactRelationCache(bool commit) AtEOXact_RelationCache(bool commit)
{ {
HASH_SEQ_STATUS status; HASH_SEQ_STATUS status;
RelIdCacheEnt *idhentry; RelIdCacheEnt *idhentry;
#ifdef USE_ASSERT_CHECKING
if (commit && IsBootstrapProcessingMode())
return;
#else
if (commit)
return;
#endif
hash_seq_init(&status, RelationIdCache); hash_seq_init(&status, RelationIdCache);
while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL) while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
...@@ -2006,11 +1960,45 @@ AtEOXactRelationCache(bool commit) ...@@ -2006,11 +1960,45 @@ AtEOXactRelationCache(bool commit)
Relation relation = idhentry->reldesc; Relation relation = idhentry->reldesc;
int expected_refcnt; int expected_refcnt;
/*
* Is it a relation created in the current transaction?
*
* During commit, reset the flag to false, since we are now out of the
* creating transaction. During abort, simply delete the relcache
* entry --- it isn't interesting any longer.
*/
if (relation->rd_isnew)
{
if (commit)
relation->rd_isnew = false;
else
{
RelationClearRelation(relation, false);
continue;
}
}
/*
* During transaction abort, we must also reset relcache entry ref
* counts to their normal not-in-a-transaction state. A ref count may
* be too high because some routine was exited by elog() between
* incrementing and decrementing the count.
*
* During commit, we should not have to do this, but it's still useful
* to check that the counts are correct to catch missed relcache
* closes.
*
* In bootstrap mode, do NOT reset the refcnt nor complain that it's
* nonzero --- the bootstrap code expects relations to stay open
* across start/commit transaction calls. (That seems bogus, but it's
* not worth fixing.)
*/
expected_refcnt = relation->rd_isnailed ? 1 : 0; expected_refcnt = relation->rd_isnailed ? 1 : 0;
if (commit) if (commit)
{ {
if (relation->rd_refcnt != expected_refcnt) if (relation->rd_refcnt != expected_refcnt &&
!IsBootstrapProcessingMode())
{ {
elog(WARNING, "Relcache reference leak: relation \"%s\" has refcnt %d instead of %d", elog(WARNING, "Relcache reference leak: relation \"%s\" has refcnt %d instead of %d",
RelationGetRelationName(relation), RelationGetRelationName(relation),
...@@ -2055,10 +2043,11 @@ RelationBuildLocalRelation(const char *relname, ...@@ -2055,10 +2043,11 @@ RelationBuildLocalRelation(const char *relname,
oldcxt = MemoryContextSwitchTo(CacheMemoryContext); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* /*
* allocate a new relation descriptor. * allocate a new relation descriptor and fill in basic state fields.
*/ */
rel = (Relation) palloc(sizeof(RelationData)); rel = (Relation) palloc(sizeof(RelationData));
MemSet((char *) rel, 0, sizeof(RelationData)); MemSet((char *) rel, 0, sizeof(RelationData));
rel->rd_targblock = InvalidBlockNumber; rel->rd_targblock = InvalidBlockNumber;
/* make sure relation is marked as having no open file yet */ /* make sure relation is marked as having no open file yet */
...@@ -2066,6 +2055,12 @@ RelationBuildLocalRelation(const char *relname, ...@@ -2066,6 +2055,12 @@ RelationBuildLocalRelation(const char *relname,
RelationSetReferenceCount(rel, 1); RelationSetReferenceCount(rel, 1);
/* it's being created in this transaction */
rel->rd_isnew = true;
/* is it a temporary relation? */
rel->rd_istemp = isTempNamespace(relnamespace);
/* /*
* nail the reldesc if this is a bootstrap create reln and we may need * nail the reldesc if this is a bootstrap create reln and we may need
* it in the cache later on in the bootstrap process so we don't ever * it in the cache later on in the bootstrap process so we don't ever
...@@ -2121,17 +2116,6 @@ RelationBuildLocalRelation(const char *relname, ...@@ -2121,17 +2116,6 @@ RelationBuildLocalRelation(const char *relname,
*/ */
RelationCacheInsert(rel); RelationCacheInsert(rel);
/*
* we've just created the relation. It is invisible to anyone else
* before the transaction is committed. Setting rd_myxactonly allows
* us to use the local buffer manager for select/insert/etc before the
* end of transaction. (We also need to keep track of relations
* created during a transaction and do the necessary clean up at the
* end of the transaction.) - ay 3/95
*/
rel->rd_myxactonly = true;
newlyCreatedRelns = lcons(rel, newlyCreatedRelns);
/* /*
* done building relcache entry. * done building relcache entry.
*/ */
...@@ -2140,38 +2124,6 @@ RelationBuildLocalRelation(const char *relname, ...@@ -2140,38 +2124,6 @@ RelationBuildLocalRelation(const char *relname,
return rel; return rel;
} }
/*
* RelationPurgeLocalRelation -
* find all the Relation descriptors marked rd_myxactonly and reset them.
* This should be called at the end of a transaction (commit/abort) when
* the "local" relations will become visible to others and the multi-user
* buffer pool should be used.
*/
void
RelationPurgeLocalRelation(bool xactCommitted)
{
while (newlyCreatedRelns)
{
List *l = newlyCreatedRelns;
Relation reln = lfirst(l);
newlyCreatedRelns = lnext(newlyCreatedRelns);
pfree(l);
Assert(reln != NULL && reln->rd_myxactonly);
reln->rd_myxactonly = false; /* mark it not on list anymore */
/*
* XXX while we clearly must throw out new Relation entries at
* xact abort, it's not clear why we need to do it at commit.
* Could this be improved?
*/
if (!IsBootstrapProcessingMode())
RelationClearRelation(reln, false);
}
}
/* /*
* RelationCacheInitialize * RelationCacheInitialize
* *
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: xlog.h,v 1.33 2002/08/05 01:24:16 thomas Exp $ * $Id: xlog.h,v 1.34 2002/08/06 02:36:35 tgl Exp $
*/ */
#ifndef XLOG_H #ifndef XLOG_H
#define XLOG_H #define XLOG_H
...@@ -182,6 +182,7 @@ extern StartUpID ThisStartUpID; /* current SUI */ ...@@ -182,6 +182,7 @@ extern StartUpID ThisStartUpID; /* current SUI */
extern bool InRecovery; extern bool InRecovery;
extern XLogRecPtr MyLastRecPtr; extern XLogRecPtr MyLastRecPtr;
extern bool MyXactMadeXLogEntry; extern bool MyXactMadeXLogEntry;
extern bool MyXactMadeTempRelUpdate;
extern XLogRecPtr ProcLastRecEnd; extern XLogRecPtr ProcLastRecEnd;
/* these variables are GUC parameters related to XLOG */ /* these variables are GUC parameters related to XLOG */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: buf_internals.h,v 1.57 2002/06/20 20:29:52 momjian Exp $ * $Id: buf_internals.h,v 1.58 2002/08/06 02:36:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -149,6 +149,15 @@ typedef struct _bmtrace ...@@ -149,6 +149,15 @@ typedef struct _bmtrace
#endif /* BMTRACE */ #endif /* BMTRACE */
/* counters in buf_init.c */
extern long int ReadBufferCount;
extern long int ReadLocalBufferCount;
extern long int BufferHitCount;
extern long int LocalBufferHitCount;
extern long int BufferFlushCount;
extern long int LocalBufferFlushCount;
/* /*
* Bufmgr Interface: * Bufmgr Interface:
*/ */
...@@ -177,8 +186,6 @@ extern BufferDesc *LocalBufferDescriptors; ...@@ -177,8 +186,6 @@ extern BufferDesc *LocalBufferDescriptors;
extern BufferDesc *LocalBufferAlloc(Relation reln, BlockNumber blockNum, extern BufferDesc *LocalBufferAlloc(Relation reln, BlockNumber blockNum,
bool *foundPtr); bool *foundPtr);
extern void WriteLocalBuffer(Buffer buffer, bool release); extern void WriteLocalBuffer(Buffer buffer, bool release);
extern int FlushLocalBuffer(Buffer buffer, bool sync, bool release); extern void AtEOXact_LocalBuffers(bool isCommit);
extern void LocalBufferSync(void);
extern void ResetLocalBufferPool(void);
#endif /* BUFMGR_INTERNALS_H */ #endif /* BUFMGR_INTERNALS_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: bufmgr.h,v 1.61 2002/07/02 05:47:37 momjian Exp $ * $Id: bufmgr.h,v 1.62 2002/08/06 02:36:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -152,20 +152,18 @@ extern void WriteBuffer(Buffer buffer); ...@@ -152,20 +152,18 @@ extern void WriteBuffer(Buffer buffer);
extern void WriteNoReleaseBuffer(Buffer buffer); extern void WriteNoReleaseBuffer(Buffer buffer);
extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation,
BlockNumber blockNum); BlockNumber blockNum);
extern int FlushBuffer(Buffer buffer, bool sync, bool release);
extern void InitBufferPool(void); extern void InitBufferPool(void);
extern void InitBufferPoolAccess(void); extern void InitBufferPoolAccess(void);
extern char *ShowBufferUsage(void); extern char *ShowBufferUsage(void);
extern void ResetBufferUsage(void); extern void ResetBufferUsage(void);
extern void ResetBufferPool(bool isCommit); extern void AtEOXact_Buffers(bool isCommit);
extern bool BufferPoolCheckLeak(void);
extern void FlushBufferPool(void); extern void FlushBufferPool(void);
extern BlockNumber BufferGetBlockNumber(Buffer buffer); extern BlockNumber BufferGetBlockNumber(Buffer buffer);
extern BlockNumber RelationGetNumberOfBlocks(Relation relation); extern BlockNumber RelationGetNumberOfBlocks(Relation relation);
extern int FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock); extern int FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock);
extern void DropRelationBuffers(Relation rel); extern void DropRelationBuffers(Relation rel);
extern void DropRelFileNodeBuffers(RelFileNode rnode); extern void DropRelFileNodeBuffers(RelFileNode rnode, bool istemp);
extern void DropBuffers(Oid dbid); extern void DropBuffers(Oid dbid);
#ifdef NOT_USED #ifdef NOT_USED
extern void PrintPinnedBufs(void); extern void PrintPinnedBufs(void);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: fd.h,v 1.35 2002/06/20 20:29:52 momjian Exp $ * $Id: fd.h,v 1.36 2002/08/06 02:36:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -62,8 +62,6 @@ extern int FileRead(File file, char *buffer, int amount); ...@@ -62,8 +62,6 @@ extern int FileRead(File file, char *buffer, int amount);
extern int FileWrite(File file, char *buffer, int amount); extern int FileWrite(File file, char *buffer, int amount);
extern long FileSeek(File file, long offset, int whence); extern long FileSeek(File file, long offset, int whence);
extern int FileTruncate(File file, long offset); extern int FileTruncate(File file, long offset);
extern int FileSync(File file);
extern void FileMarkDirty(File file);
/* Operations that allow use of regular stdio --- USE WITH CAUTION */ /* Operations that allow use of regular stdio --- USE WITH CAUTION */
extern FILE *AllocateFile(char *name, char *mode); extern FILE *AllocateFile(char *name, char *mode);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: smgr.h,v 1.35 2002/06/20 20:29:52 momjian Exp $ * $Id: smgr.h,v 1.36 2002/08/06 02:36:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -36,13 +36,8 @@ extern int smgrread(int16 which, Relation reln, BlockNumber blocknum, ...@@ -36,13 +36,8 @@ extern int smgrread(int16 which, Relation reln, BlockNumber blocknum,
char *buffer); char *buffer);
extern int smgrwrite(int16 which, Relation reln, BlockNumber blocknum, extern int smgrwrite(int16 which, Relation reln, BlockNumber blocknum,
char *buffer); char *buffer);
extern int smgrflush(int16 which, Relation reln, BlockNumber blocknum,
char *buffer);
extern int smgrblindwrt(int16 which, RelFileNode rnode, extern int smgrblindwrt(int16 which, RelFileNode rnode,
BlockNumber blkno, char *buffer, bool dofsync); BlockNumber blkno, char *buffer);
extern int smgrblindmarkdirty(int16 which, RelFileNode rnode,
BlockNumber blkno);
extern int smgrmarkdirty(int16 which, Relation reln, BlockNumber blkno);
extern BlockNumber smgrnblocks(int16 which, Relation reln); extern BlockNumber smgrnblocks(int16 which, Relation reln);
extern BlockNumber smgrtruncate(int16 which, Relation reln, extern BlockNumber smgrtruncate(int16 which, Relation reln,
BlockNumber nblocks); BlockNumber nblocks);
...@@ -67,11 +62,7 @@ extern int mdopen(Relation reln); ...@@ -67,11 +62,7 @@ extern int mdopen(Relation reln);
extern int mdclose(Relation reln); extern int mdclose(Relation reln);
extern int mdread(Relation reln, BlockNumber blocknum, char *buffer); extern int mdread(Relation reln, BlockNumber blocknum, char *buffer);
extern int mdwrite(Relation reln, BlockNumber blocknum, char *buffer); extern int mdwrite(Relation reln, BlockNumber blocknum, char *buffer);
extern int mdflush(Relation reln, BlockNumber blocknum, char *buffer); extern int mdblindwrt(RelFileNode rnode, BlockNumber blkno, char *buffer);
extern int mdmarkdirty(Relation reln, BlockNumber blkno);
extern int mdblindwrt(RelFileNode rnode, BlockNumber blkno,
char *buffer, bool dofsync);
extern int mdblindmarkdirty(RelFileNode rnode, BlockNumber blkno);
extern BlockNumber mdnblocks(Relation reln); extern BlockNumber mdnblocks(Relation reln);
extern BlockNumber mdtruncate(Relation reln, BlockNumber nblocks); extern BlockNumber mdtruncate(Relation reln, BlockNumber nblocks);
extern int mdcommit(void); extern int mdcommit(void);
...@@ -87,13 +78,7 @@ extern int mmopen(Relation reln); ...@@ -87,13 +78,7 @@ extern int mmopen(Relation reln);
extern int mmclose(Relation reln); extern int mmclose(Relation reln);
extern int mmread(Relation reln, BlockNumber blocknum, char *buffer); extern int mmread(Relation reln, BlockNumber blocknum, char *buffer);
extern int mmwrite(Relation reln, BlockNumber blocknum, char *buffer); extern int mmwrite(Relation reln, BlockNumber blocknum, char *buffer);
extern int mmflush(Relation reln, BlockNumber blocknum, char *buffer); extern int mmblindwrt(RelFileNode rnode, BlockNumber blkno, char *buffer);
extern int mmblindwrt(char *dbname, char *relname, Oid dbid, Oid relid,
BlockNumber blkno, char *buffer,
bool dofsync);
extern int mmmarkdirty(Relation reln, BlockNumber blkno);
extern int mmblindmarkdirty(char *dbname, char *relname, Oid dbid, Oid relid,
BlockNumber blkno);
extern BlockNumber mmnblocks(Relation reln); extern BlockNumber mmnblocks(Relation reln);
extern BlockNumber mmtruncate(Relation reln, BlockNumber nblocks); extern BlockNumber mmtruncate(Relation reln, BlockNumber nblocks);
extern int mmcommit(void); extern int mmcommit(void);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: rel.h,v 1.60 2002/06/20 20:29:53 momjian Exp $ * $Id: rel.h,v 1.61 2002/08/06 02:36:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -112,10 +112,10 @@ typedef struct RelationData ...@@ -112,10 +112,10 @@ typedef struct RelationData
BlockNumber rd_targblock; /* current insertion target block, or BlockNumber rd_targblock; /* current insertion target block, or
* InvalidBlockNumber */ * InvalidBlockNumber */
int rd_refcnt; /* reference count */ int rd_refcnt; /* reference count */
bool rd_myxactonly; /* rel uses the local buffer mgr */ bool rd_isnew; /* rel was created in current xact */
bool rd_istemp; /* rel uses the local buffer mgr */
bool rd_isnailed; /* rel is nailed in cache */ bool rd_isnailed; /* rel is nailed in cache */
bool rd_indexfound; /* true if rd_indexlist is valid */ bool rd_indexfound; /* true if rd_indexlist is valid */
bool rd_uniqueindex; /* true if rel is a UNIQUE index */
Form_pg_class rd_rel; /* RELATION tuple */ Form_pg_class rd_rel; /* RELATION tuple */
TupleDesc rd_att; /* tuple descriptor */ TupleDesc rd_att; /* tuple descriptor */
Oid rd_id; /* relation's object id */ Oid rd_id; /* relation's object id */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: relcache.h,v 1.33 2002/08/02 22:36:05 tgl Exp $ * $Id: relcache.h,v 1.34 2002/08/06 02:36:35 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -61,9 +61,7 @@ extern void RelationIdInvalidateRelationCacheByRelationId(Oid relationId); ...@@ -61,9 +61,7 @@ extern void RelationIdInvalidateRelationCacheByRelationId(Oid relationId);
extern void RelationCacheInvalidate(void); extern void RelationCacheInvalidate(void);
extern void RelationPurgeLocalRelation(bool xactComitted); extern void AtEOXact_RelationCache(bool commit);
extern void AtEOXactRelationCache(bool commit);
/* /*
* Routines to help manage rebuilding of relcache init file * Routines to help manage rebuilding of relcache init file
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment