From 9ffc8ed58b55cb3925bb95cc184583fcb9772013 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Fri, 15 Oct 2004 22:40:29 +0000 Subject: [PATCH] Repair possible failure to update hint bits back to disk, per http://archives.postgresql.org/pgsql-hackers/2004-10/msg00464.php. This fix is intended to be permanent: it moves the responsibility for calling SetBufferCommitInfoNeedsSave() into the tqual.c routines, eliminating the requirement for callers to test whether t_infomask changed. Also, tighten validity checking on buffer IDs in bufmgr.c --- several routines were paranoid about out-of-range shared buffer numbers but not about out-of-range local ones, which seems a tad pointless. --- contrib/pgstattuple/pgstattuple.c | 11 +- src/backend/access/heap/heapam.c | 18 ++-- src/backend/access/index/indexam.c | 14 +-- src/backend/access/nbtree/nbtinsert.c | 12 +-- src/backend/catalog/index.c | 18 ++-- src/backend/commands/vacuum.c | 17 ++- src/backend/commands/vacuumlazy.c | 33 ++---- src/backend/storage/buffer/bufmgr.c | 33 +++--- src/backend/utils/adt/ri_triggers.c | 9 +- src/backend/utils/time/tqual.c | 149 ++++++++++++++++++++++---- src/include/access/valid.h | 45 +++----- src/include/storage/bufmgr.h | 24 ++--- src/include/utils/tqual.h | 34 +++--- 13 files changed, 241 insertions(+), 176 deletions(-) diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c index bfe37eb9ed6..e2fab7863eb 100644 --- a/contrib/pgstattuple/pgstattuple.c +++ b/contrib/pgstattuple/pgstattuple.c @@ -1,5 +1,5 @@ /* - * $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.16 2004/08/29 05:06:37 momjian Exp $ + * $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.17 2004/10/15 22:39:38 tgl Exp $ * * Copyright (c) 2001,2002 Tatsuo Ishii * @@ -134,7 +134,10 @@ pgstattuple_real(Relation rel) /* scan the relation */ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { - if (HeapTupleSatisfiesNow(tuple->t_data)) + /* must hold a buffer lock to call HeapTupleSatisfiesNow */ + LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); + + if (HeapTupleSatisfiesNow(tuple->t_data, scan->rs_cbuf)) { tuple_len += tuple->t_len; tuple_count++; @@ -145,6 +148,8 @@ pgstattuple_real(Relation rel) dead_tuple_count++; } + LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK); + /* * To avoid physically reading the table twice, try to do the * free-space scan in parallel with the heap scan. However, @@ -156,7 +161,9 @@ pgstattuple_real(Relation rel) while (block <= tupblock) { buffer = ReadBuffer(rel, block); + LockBuffer(buffer, BUFFER_LOCK_SHARE); free_space += PageGetFreeSpace((Page) BufferGetPage(buffer)); + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); ReleaseBuffer(buffer); block++; } diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index b9a6072c799..af5325ea632 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.178 2004/10/12 21:54:34 petere Exp $ + * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.179 2004/10/15 22:39:42 tgl Exp $ * * * INTERFACE ROUTINES @@ -1314,7 +1314,7 @@ heap_delete(Relation relation, ItemPointer tid, tp.t_tableOid = relation->rd_id; l1: - result = HeapTupleSatisfiesUpdate(tp.t_data, cid); + result = HeapTupleSatisfiesUpdate(tp.t_data, cid, buffer); if (result == HeapTupleInvisible) { @@ -1331,7 +1331,7 @@ l1: XactLockTableWait(xwait); LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); - if (TransactionIdDidAbort(xwait)) + if (!TransactionIdDidCommit(xwait)) goto l1; /* @@ -1356,7 +1356,7 @@ l1: if (crosscheck != InvalidSnapshot && result == HeapTupleMayBeUpdated) { /* Perform additional check for serializable RI updates */ - if (!HeapTupleSatisfiesSnapshot(tp.t_data, crosscheck)) + if (!HeapTupleSatisfiesSnapshot(tp.t_data, crosscheck, buffer)) result = HeapTupleUpdated; } @@ -1543,7 +1543,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, */ l2: - result = HeapTupleSatisfiesUpdate(oldtup.t_data, cid); + result = HeapTupleSatisfiesUpdate(oldtup.t_data, cid, buffer); if (result == HeapTupleInvisible) { @@ -1560,7 +1560,7 @@ l2: XactLockTableWait(xwait); LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); - if (TransactionIdDidAbort(xwait)) + if (!TransactionIdDidCommit(xwait)) goto l2; /* @@ -1585,7 +1585,7 @@ l2: if (crosscheck != InvalidSnapshot && result == HeapTupleMayBeUpdated) { /* Perform additional check for serializable RI updates */ - if (!HeapTupleSatisfiesSnapshot(oldtup.t_data, crosscheck)) + if (!HeapTupleSatisfiesSnapshot(oldtup.t_data, crosscheck, buffer)) result = HeapTupleUpdated; } @@ -1871,7 +1871,7 @@ heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer, tuple->t_len = ItemIdGetLength(lp); l3: - result = HeapTupleSatisfiesUpdate(tuple->t_data, cid); + result = HeapTupleSatisfiesUpdate(tuple->t_data, cid, *buffer); if (result == HeapTupleInvisible) { @@ -1888,7 +1888,7 @@ l3: XactLockTableWait(xwait); LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE); - if (TransactionIdDidAbort(xwait)) + if (!TransactionIdDidCommit(xwait)) goto l3; /* diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index 7c698fb48a2..214f646276b 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.75 2004/09/30 23:21:14 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.76 2004/10/15 22:39:46 tgl Exp $ * * INTERFACE ROUTINES * index_open - open an index relation by relation OID @@ -497,7 +497,6 @@ index_getnext(IndexScanDesc scan, ScanDirection direction) for (;;) { bool found; - uint16 sv_infomask; pgstat_count_index_scan(&scan->xs_pgstat_info); @@ -541,19 +540,14 @@ index_getnext(IndexScanDesc scan, ScanDirection direction) * index AM to not return it on future indexscans. * * We told heap_release_fetch to keep a pin on the buffer, so we can - * re-access the tuple here. But we must re-lock the buffer - * first. Also, it's just barely possible for an update of hint - * bits to occur here. + * re-access the tuple here. But we must re-lock the buffer first. */ LockBuffer(scan->xs_cbuf, BUFFER_LOCK_SHARE); - sv_infomask = heapTuple->t_data->t_infomask; - if (HeapTupleSatisfiesVacuum(heapTuple->t_data, RecentGlobalXmin) == - HEAPTUPLE_DEAD) + if (HeapTupleSatisfiesVacuum(heapTuple->t_data, RecentGlobalXmin, + scan->xs_cbuf) == HEAPTUPLE_DEAD) scan->kill_prior_tuple = true; - if (sv_infomask != heapTuple->t_data->t_infomask) - SetBufferCommitInfoNeedsSave(scan->xs_cbuf); LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK); } diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index 815e207fb2f..32615a62c27 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.116 2004/08/29 05:06:40 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.117 2004/10/15 22:39:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -261,19 +261,13 @@ _bt_check_unique(Relation rel, BTItem btitem, Relation heapRel, * marked killed. This logic should match * index_getnext and btgettuple. */ - uint16 sv_infomask; - LockBuffer(hbuffer, BUFFER_LOCK_SHARE); - sv_infomask = htup.t_data->t_infomask; - if (HeapTupleSatisfiesVacuum(htup.t_data, - RecentGlobalXmin) == - HEAPTUPLE_DEAD) + if (HeapTupleSatisfiesVacuum(htup.t_data, RecentGlobalXmin, + hbuffer) == HEAPTUPLE_DEAD) { curitemid->lp_flags |= LP_DELETE; SetBufferCommitInfoNeedsSave(buf); } - if (sv_infomask != htup.t_data->t_infomask) - SetBufferCommitInfoNeedsSave(hbuffer); LockBuffer(hbuffer, BUFFER_LOCK_UNLOCK); ReleaseBuffer(hbuffer); } diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 8fb2f8f4f22..19fc60b6c88 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.240 2004/10/01 17:11:49 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.241 2004/10/15 22:39:53 tgl Exp $ * * * INTERFACE ROUTINES @@ -1472,18 +1472,16 @@ IndexBuildHeapScan(Relation heapRelation, { /* do our own time qual check */ bool indexIt; - uint16 sv_infomask; /* - * HeapTupleSatisfiesVacuum may update tuple's hint status - * bits. We could possibly get away with not locking the - * buffer here, since caller should hold ShareLock on the - * relation, but let's be conservative about it. + * We could possibly get away with not locking the buffer here, + * since caller should hold ShareLock on the relation, but let's + * be conservative about it. */ LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); - sv_infomask = heapTuple->t_data->t_infomask; - switch (HeapTupleSatisfiesVacuum(heapTuple->t_data, OldestXmin)) + switch (HeapTupleSatisfiesVacuum(heapTuple->t_data, OldestXmin, + scan->rs_cbuf)) { case HEAPTUPLE_DEAD: indexIt = false; @@ -1544,10 +1542,6 @@ IndexBuildHeapScan(Relation heapRelation, break; } - /* check for hint-bit update by HeapTupleSatisfiesVacuum */ - if (sv_infomask != heapTuple->t_data->t_infomask) - SetBufferCommitInfoNeedsSave(scan->rs_cbuf); - LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK); if (!indexIt) diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 232ec9a89e6..3d0c6e0e996 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.294 2004/10/07 14:19:58 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.295 2004/10/15 22:39:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1190,6 +1190,12 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, buf = ReadBuffer(onerel, blkno); page = BufferGetPage(buf); + /* + * We don't bother to do LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE) + * because we assume that holding exclusive lock on the relation + * will keep other backends from looking at the page. + */ + vacpage->blkno = blkno; vacpage->offsets_used = 0; vacpage->offsets_free = 0; @@ -1235,7 +1241,6 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, offnum <= maxoff; offnum = OffsetNumberNext(offnum)) { - uint16 sv_infomask; ItemId itemid = PageGetItemId(page, offnum); bool tupgone = false; @@ -1255,9 +1260,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, tuple.t_len = ItemIdGetLength(itemid); ItemPointerSet(&(tuple.t_self), blkno, offnum); - sv_infomask = tuple.t_data->t_infomask; - - switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin)) + switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin, buf)) { case HEAPTUPLE_DEAD: tupgone = true; /* we can delete the tuple */ @@ -1348,10 +1351,6 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, break; } - /* check for hint-bit update by HeapTupleSatisfiesVacuum */ - if (sv_infomask != tuple.t_data->t_infomask) - pgchanged = true; - if (tupgone) { ItemId lpp; diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index ebdb27f336f..62ba05f9698 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -31,7 +31,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.46 2004/09/30 23:21:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.47 2004/10/15 22:39:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -291,7 +291,6 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, offnum = OffsetNumberNext(offnum)) { ItemId itemid; - uint16 sv_infomask; itemid = PageGetItemId(page, offnum); @@ -307,9 +306,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, ItemPointerSet(&(tuple.t_self), blkno, offnum); tupgone = false; - sv_infomask = tuple.t_data->t_infomask; - switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin)) + switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin, buf)) { case HEAPTUPLE_DEAD: tupgone = true; /* we can delete the tuple */ @@ -364,10 +362,6 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, break; } - /* check for hint-bit update by HeapTupleSatisfiesVacuum */ - if (sv_infomask != tuple.t_data->t_infomask) - pgchanged = true; - if (tupgone) { lazy_record_dead_tuple(vacrelstats, &(tuple.t_self)); @@ -399,9 +393,9 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, LockBuffer(buf, BUFFER_LOCK_UNLOCK); if (pgchanged) - SetBufferCommitInfoNeedsSave(buf); - - ReleaseBuffer(buf); + WriteBuffer(buf); + else + ReleaseBuffer(buf); } /* save stats for use later */ @@ -790,8 +784,7 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) Page page; OffsetNumber offnum, maxoff; - bool pgchanged, - tupgone, + bool tupgone, hastup; vacuum_delay_point(); @@ -813,7 +806,6 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) continue; } - pgchanged = false; hastup = false; maxoff = PageGetMaxOffsetNumber(page); for (offnum = FirstOffsetNumber; @@ -821,7 +813,6 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) offnum = OffsetNumberNext(offnum)) { ItemId itemid; - uint16 sv_infomask; itemid = PageGetItemId(page, offnum); @@ -834,9 +825,8 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) ItemPointerSet(&(tuple.t_self), blkno, offnum); tupgone = false; - sv_infomask = tuple.t_data->t_infomask; - switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin)) + switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin, buf)) { case HEAPTUPLE_DEAD: tupgone = true; /* we can delete the tuple */ @@ -862,10 +852,6 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) break; } - /* check for hint-bit update by HeapTupleSatisfiesVacuum */ - if (sv_infomask != tuple.t_data->t_infomask) - pgchanged = true; - if (!tupgone) { hastup = true; @@ -875,10 +861,7 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) LockBuffer(buf, BUFFER_LOCK_UNLOCK); - if (pgchanged) - WriteBuffer(buf); - else - ReleaseBuffer(buf); + ReleaseBuffer(buf); /* Done scanning if we found a tuple here */ if (hastup) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index b98193ad38c..a0f2bf9c117 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.177 2004/09/06 17:31:32 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.178 2004/10/15 22:39:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -477,15 +477,15 @@ write_buffer(Buffer buffer, bool release) { BufferDesc *bufHdr; + if (!BufferIsValid(buffer)) + elog(ERROR, "bad buffer id: %d", buffer); + if (BufferIsLocal(buffer)) { WriteLocalBuffer(buffer, release); return; } - if (BAD_BUFFER_ID(buffer)) - elog(ERROR, "bad buffer id: %d", buffer); - bufHdr = &BufferDescriptors[buffer - 1]; Assert(PrivateRefCount[buffer - 1] > 0); @@ -1465,6 +1465,9 @@ ReleaseBuffer(Buffer buffer) { BufferDesc *bufHdr; + if (!BufferIsValid(buffer)) + elog(ERROR, "bad buffer id: %d", buffer); + ResourceOwnerForgetBuffer(CurrentResourceOwner, buffer); if (BufferIsLocal(buffer)) @@ -1474,9 +1477,6 @@ ReleaseBuffer(Buffer buffer) return; } - if (BAD_BUFFER_ID(buffer)) - elog(ERROR, "bad buffer id: %d", buffer); - bufHdr = &BufferDescriptors[buffer - 1]; Assert(PrivateRefCount[buffer - 1] > 0); @@ -1503,17 +1503,16 @@ ReleaseBuffer(Buffer buffer) void IncrBufferRefCount(Buffer buffer) { + Assert(BufferIsValid(buffer)); ResourceOwnerEnlargeBuffers(CurrentResourceOwner); ResourceOwnerRememberBuffer(CurrentResourceOwner, buffer); if (BufferIsLocal(buffer)) { - Assert(buffer >= -NLocBuffer); Assert(LocalRefCount[-buffer - 1] > 0); LocalRefCount[-buffer - 1]++; } else { - Assert(!BAD_BUFFER_ID(buffer)); Assert(PrivateRefCount[buffer - 1] > 0); PrivateRefCount[buffer - 1]++; } @@ -1606,9 +1605,12 @@ ReleaseAndReadBuffer_Debug(char *file, * * Mark a buffer dirty when we have updated tuple commit-status bits in it. * - * This is similar to WriteNoReleaseBuffer, except that we have not made a - * critical change that has to be flushed to disk before xact commit --- the - * status-bit update could be redone by someone else just as easily. + * This is essentially the same as WriteNoReleaseBuffer. We preserve the + * distinction as a way of documenting that the caller has not made a critical + * data change --- the status-bit update could be redone by someone else just + * as easily. Therefore, no WAL log record need be generated, whereas calls + * to WriteNoReleaseBuffer really ought to be associated with a WAL-entry- + * creating action. * * This routine might get called many times on the same page, if we are making * the first scan after commit of an xact that added/deleted many tuples. @@ -1623,15 +1625,15 @@ SetBufferCommitInfoNeedsSave(Buffer buffer) { BufferDesc *bufHdr; + if (!BufferIsValid(buffer)) + elog(ERROR, "bad buffer id: %d", buffer); + if (BufferIsLocal(buffer)) { WriteLocalBuffer(buffer, false); return; } - if (BAD_BUFFER_ID(buffer)) - elog(ERROR, "bad buffer id: %d", buffer); - bufHdr = &BufferDescriptors[buffer - 1]; if ((bufHdr->flags & (BM_DIRTY | BM_JUST_DIRTIED)) != @@ -1662,7 +1664,6 @@ UnlockBuffers(void) if (buflocks == 0) continue; - Assert(BufferIsValid(i + 1)); buf = &(BufferDescriptors[i]); HOLD_INTERRUPTS(); /* don't want to die() partway through... */ diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 20ad56c31f1..b195e243393 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -17,7 +17,7 @@ * * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.73 2004/09/13 20:07:13 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.74 2004/10/15 22:40:11 tgl Exp $ * * ---------- */ @@ -224,10 +224,15 @@ RI_FKey_check(PG_FUNCTION_ARGS) * We should not even consider checking the row if it is no longer * valid since it was either deleted (doesn't matter) or updated (in * which case it'll be checked with its final values). + * + * We do not know what buffer the new_row is in, but it doesn't matter + * since it's not possible for a hint-bit update to occur here (the + * new_row could only contain our own XID, and we haven't yet committed + * or aborted...) */ if (new_row) { - if (!HeapTupleSatisfiesItself(new_row->t_data)) + if (!HeapTupleSatisfiesItself(new_row->t_data, InvalidBuffer)) { heap_close(pk_rel, RowShareLock); return PointerGetDatum(NULL); diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c index 3adab87ace4..f36e2c13b6c 100644 --- a/src/backend/utils/time/tqual.c +++ b/src/backend/utils/time/tqual.c @@ -3,20 +3,20 @@ * tqual.c * POSTGRES "time" qualification code, ie, tuple visibility rules. * - * NOTE: all the HeapTupleSatisfies routines will update the tuple's - * "hint" status bits if we see that the inserting or deleting transaction - * has now committed or aborted. The caller is responsible for noticing any - * change in t_infomask and scheduling a disk write if so. Note that the - * caller must hold at least a shared buffer context lock on the buffer + * The caller must hold at least a shared buffer context lock on the buffer * containing the tuple. (VACUUM FULL assumes it's sufficient to have * exclusive lock on the containing relation, instead.) * + * NOTE: all the HeapTupleSatisfies routines will update the tuple's + * "hint" status bits if we see that the inserting or deleting transaction + * has now committed or aborted. + * * * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.79 2004/09/16 18:35:22 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.80 2004/10/15 22:40:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -78,7 +78,7 @@ TransactionId RecentGlobalXmin = InvalidTransactionId; * Xmax is not committed))) that has not been committed */ bool -HeapTupleSatisfiesItself(HeapTupleHeader tuple) +HeapTupleSatisfiesItself(HeapTupleHeader tuple, Buffer buffer) { if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { @@ -96,9 +96,11 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple) if (TransactionIdDidCommit(xvac)) { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return false; } tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); } } else if (tuple->t_infomask & HEAP_MOVED_IN) @@ -110,10 +112,14 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple) if (TransactionIdIsInProgress(xvac)) return false; if (TransactionIdDidCommit(xvac)) + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } else { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return false; } } @@ -127,6 +133,7 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple) if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) { tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return true; } @@ -140,11 +147,17 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple) else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) { if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple))) - tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */ + { + tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); + } return false; } else + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } } /* by here, the inserting transaction has committed */ @@ -169,7 +182,10 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple) if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple))) { if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) - tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */ + { + tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); + } return true; } @@ -178,10 +194,12 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple) if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) { tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return true; } tuple->t_infomask |= HEAP_XMAX_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); return false; } @@ -228,7 +246,7 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple) * that do catalog accesses. this is unfortunate, but not critical. */ bool -HeapTupleSatisfiesNow(HeapTupleHeader tuple) +HeapTupleSatisfiesNow(HeapTupleHeader tuple, Buffer buffer) { if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { @@ -246,9 +264,11 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple) if (TransactionIdDidCommit(xvac)) { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return false; } tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); } } else if (tuple->t_infomask & HEAP_MOVED_IN) @@ -260,10 +280,14 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple) if (TransactionIdIsInProgress(xvac)) return false; if (TransactionIdDidCommit(xvac)) + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } else { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return false; } } @@ -280,6 +304,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple) if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) { tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return true; } @@ -296,11 +321,17 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple) else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) { if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple))) - tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */ + { + tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); + } return false; } else + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } } /* by here, the inserting transaction has committed */ @@ -328,7 +359,10 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple) if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple))) { if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) - tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */ + { + tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); + } return true; } @@ -337,10 +371,12 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple) if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) { tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return true; } tuple->t_infomask |= HEAP_XMAX_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); return false; } @@ -359,7 +395,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple) * table. */ bool -HeapTupleSatisfiesToast(HeapTupleHeader tuple) +HeapTupleSatisfiesToast(HeapTupleHeader tuple, Buffer buffer) { if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { @@ -377,9 +413,11 @@ HeapTupleSatisfiesToast(HeapTupleHeader tuple) if (TransactionIdDidCommit(xvac)) { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return false; } tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); } } else if (tuple->t_infomask & HEAP_MOVED_IN) @@ -391,10 +429,14 @@ HeapTupleSatisfiesToast(HeapTupleHeader tuple) if (TransactionIdIsInProgress(xvac)) return false; if (TransactionIdDidCommit(xvac)) + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } else { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return false; } } @@ -414,7 +456,8 @@ HeapTupleSatisfiesToast(HeapTupleHeader tuple) * CurrentCommandId. */ int -HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid) +HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid, + Buffer buffer) { if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { @@ -432,9 +475,11 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid) if (TransactionIdDidCommit(xvac)) { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return HeapTupleInvisible; } tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); } } else if (tuple->t_infomask & HEAP_MOVED_IN) @@ -446,10 +491,14 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid) if (TransactionIdIsInProgress(xvac)) return HeapTupleInvisible; if (TransactionIdDidCommit(xvac)) + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } else { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return HeapTupleInvisible; } } @@ -467,6 +516,7 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid) if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) { tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return HeapTupleMayBeUpdated; } @@ -485,11 +535,17 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid) else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) { if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple))) - tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */ + { + tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); + } return HeapTupleInvisible; } else + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } } /* by here, the inserting transaction has committed */ @@ -519,7 +575,8 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid) { if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) { - tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */ + tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return HeapTupleMayBeUpdated; } /* running xact */ @@ -531,10 +588,12 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid) if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) { tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return HeapTupleMayBeUpdated; } tuple->t_infomask |= HEAP_XMAX_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); return HeapTupleUpdated; /* updated by other */ } @@ -556,7 +615,7 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid) * t_ctid (forward link) is returned if it's being updated. */ bool -HeapTupleSatisfiesDirty(HeapTupleHeader tuple) +HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Buffer buffer) { SnapshotDirty->xmin = SnapshotDirty->xmax = InvalidTransactionId; ItemPointerSetInvalid(&(SnapshotDirty->tid)); @@ -577,9 +636,11 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple) if (TransactionIdDidCommit(xvac)) { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return false; } tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); } } else if (tuple->t_infomask & HEAP_MOVED_IN) @@ -591,10 +652,14 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple) if (TransactionIdIsInProgress(xvac)) return false; if (TransactionIdDidCommit(xvac)) + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } else { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return false; } } @@ -608,6 +673,7 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple) if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) { tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return true; } @@ -623,6 +689,7 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple) if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple))) { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return false; } SnapshotDirty->xmin = HeapTupleHeaderGetXmin(tuple); @@ -630,7 +697,10 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple) return true; /* in insertion by other */ } else + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } } /* by here, the inserting transaction has committed */ @@ -657,7 +727,8 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple) { if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) { - tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */ + tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return true; } /* running xact */ @@ -670,10 +741,12 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple) if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) { tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return true; } tuple->t_infomask |= HEAP_XMAX_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); SnapshotDirty->tid = tuple->t_ctid; return false; /* updated by other */ } @@ -700,7 +773,8 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple) * can't see it.) */ bool -HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot) +HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot, + Buffer buffer) { if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { @@ -718,9 +792,11 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot) if (TransactionIdDidCommit(xvac)) { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return false; } tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); } } else if (tuple->t_infomask & HEAP_MOVED_IN) @@ -732,10 +808,14 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot) if (TransactionIdIsInProgress(xvac)) return false; if (TransactionIdDidCommit(xvac)) + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } else { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return false; } } @@ -753,6 +833,7 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot) if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) { tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return true; } @@ -769,11 +850,17 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot) else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) { if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple))) + { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); + } return false; } else + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } } /* @@ -831,12 +918,16 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot) if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple))) { if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple))) - tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */ + { + tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); + } return true; } /* xmax transaction committed */ tuple->t_infomask |= HEAP_XMAX_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); } /* @@ -886,7 +977,8 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot) * even if we see that the deleting transaction has committed. */ HTSV_Result -HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin) +HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin, + Buffer buffer) { /* * Has inserting transaction committed? @@ -916,9 +1008,11 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin) if (TransactionIdDidCommit(xvac)) { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return HEAPTUPLE_DEAD; } tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); } else if (tuple->t_infomask & HEAP_MOVED_IN) { @@ -929,10 +1023,14 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin) if (TransactionIdIsInProgress(xvac)) return HEAPTUPLE_INSERT_IN_PROGRESS; if (TransactionIdDidCommit(xvac)) + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } else { tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return HEAPTUPLE_DEAD; } } @@ -946,7 +1044,10 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin) return HEAPTUPLE_DELETE_IN_PROGRESS; } else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) + { tuple->t_infomask |= HEAP_XMIN_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } else { /* @@ -954,6 +1055,7 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin) * crashed */ tuple->t_infomask |= HEAP_XMIN_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return HEAPTUPLE_DEAD; } /* Should only get here if we set XMIN_COMMITTED */ @@ -986,6 +1088,7 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin) * it did not and will never actually update it. */ tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); } return HEAPTUPLE_LIVE; } @@ -995,7 +1098,10 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin) if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple))) return HEAPTUPLE_DELETE_IN_PROGRESS; else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple))) + { tuple->t_infomask |= HEAP_XMAX_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } else { /* @@ -1003,6 +1109,7 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin) * crashed */ tuple->t_infomask |= HEAP_XMAX_INVALID; + SetBufferCommitInfoNeedsSave(buffer); return HEAPTUPLE_LIVE; } /* Should only get here if we set XMAX_COMMITTED */ diff --git a/src/include/access/valid.h b/src/include/access/valid.h index 785ae80b243..62a547a181a 100644 --- a/src/include/access/valid.h +++ b/src/include/access/valid.h @@ -7,20 +7,18 @@ * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/valid.h,v 1.34 2004/08/29 04:13:04 momjian Exp $ + * $PostgreSQL: pgsql/src/include/access/valid.h,v 1.35 2004/10/15 22:40:21 tgl Exp $ * *------------------------------------------------------------------------- */ #ifndef VALID_H #define VALID_H -/* ---------------- +/* * HeapKeyTest * - * Test a heap tuple with respect to a scan key. - * ---------------- + * Test a heap tuple to see if it satisfies a scan key. */ - #define HeapKeyTest(tuple, \ tupdesc, \ nkeys, \ @@ -28,9 +26,7 @@ result) \ do \ { \ -/* We use underscores to protect the variable passed in as parameters */ \ -/* We use two underscore here because this macro is included in the \ - macro below */ \ + /* Use underscores to protect the variables passed in as parameters */ \ int __cur_nkeys = (nkeys); \ ScanKey __cur_keys = (keys); \ \ @@ -40,6 +36,12 @@ do \ Datum __atp; \ bool __isnull; \ Datum __test; \ + \ + if (__cur_keys->sk_flags & SK_ISNULL) \ + { \ + (result) = false; \ + break; \ + } \ \ __atp = heap_getattr((tuple), \ __cur_keys->sk_attno, \ @@ -47,13 +49,6 @@ do \ &__isnull); \ \ if (__isnull) \ - { \ - /* XXX eventually should check if SK_ISNULL */ \ - (result) = false; \ - break; \ - } \ - \ - if (__cur_keys->sk_flags & SK_ISNULL) \ { \ (result) = false; \ break; \ @@ -70,7 +65,7 @@ do \ } \ } while (0) -/* ---------------- +/* * HeapTupleSatisfies * * res is set TRUE if the HeapTuple satisfies the timequal and keytest, @@ -83,7 +78,6 @@ do \ * least likely to fail, too. we should really add the time qual test to * the restriction and optimize it in the normal way. this has interactions * with joey's expensive function work. - * ---------------- */ #define HeapTupleSatisfies(tuple, \ relation, \ @@ -95,24 +89,13 @@ do \ res) \ do \ { \ -/* We use underscores to protect the variable passed in as parameters */ \ if ((key) != NULL) \ - HeapKeyTest(tuple, RelationGetDescr(relation), \ - (nKeys), (key), (res)); \ + HeapKeyTest(tuple, RelationGetDescr(relation), nKeys, key, res); \ else \ (res) = true; \ \ - if (res) \ - { \ - if ((relation)->rd_rel->relkind != RELKIND_UNCATALOGED) \ - { \ - uint16 _infomask = (tuple)->t_data->t_infomask; \ - \ - (res) = HeapTupleSatisfiesVisibility((tuple), (snapshot)); \ - if ((tuple)->t_data->t_infomask != _infomask) \ - SetBufferCommitInfoNeedsSave(buffer); \ - } \ - } \ + if ((res) && (relation)->rd_rel->relkind != RELKIND_UNCATALOGED) \ + (res) = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer); \ } while (0) #endif /* VALID_H */ diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index cb8feda8bdf..04bc09e22c6 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.86 2004/08/29 05:06:58 momjian Exp $ + * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.87 2004/10/15 22:40:25 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -51,13 +51,14 @@ extern int32 *LocalRefCount; * These routines are beaten on quite heavily, hence the macroization. */ -#define BAD_BUFFER_ID(bid) ((bid) < 1 || (bid) > NBuffers) - /* * BufferIsValid * True iff the given buffer number is valid (either as a shared * or local buffer). * + * This is not quite the inverse of the BufferIsInvalid() macro, since this + * adds sanity rangechecks on the buffer number. + * * Note: For a long time this was defined the same as BufferIsPinned, * that is it would say False if you didn't hold a pin on the buffer. * I believe this was bogus and served only to mask logic errors. @@ -66,10 +67,9 @@ extern int32 *LocalRefCount; */ #define BufferIsValid(bufnum) \ ( \ - BufferIsLocal(bufnum) ? \ - ((bufnum) >= -NLocBuffer) \ - : \ - (! BAD_BUFFER_ID(bufnum)) \ + (bufnum) != InvalidBuffer && \ + (bufnum) >= -NLocBuffer && \ + (bufnum) <= NBuffers \ ) /* @@ -81,15 +81,13 @@ extern int32 *LocalRefCount; */ #define BufferIsPinned(bufnum) \ ( \ - BufferIsLocal(bufnum) ? \ - ((bufnum) >= -NLocBuffer && LocalRefCount[-(bufnum) - 1] > 0) \ + !BufferIsValid(bufnum) ? \ + false \ : \ - ( \ - BAD_BUFFER_ID(bufnum) ? \ - false \ + BufferIsLocal(bufnum) ? \ + (LocalRefCount[-(bufnum) - 1] > 0) \ : \ (PrivateRefCount[(bufnum) - 1] > 0) \ - ) \ ) /* diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h index 0854fa793a1..8aa6ed2c678 100644 --- a/src/include/utils/tqual.h +++ b/src/include/utils/tqual.h @@ -1,14 +1,14 @@ /*------------------------------------------------------------------------- * * tqual.h - * POSTGRES "time" qualification definitions, ie, tuple visibility rules. + * POSTGRES "time qualification" definitions, ie, tuple visibility rules. * * Should be moved/renamed... - vadim 07/28/98 * * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/tqual.h,v 1.53 2004/09/16 18:35:23 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/tqual.h,v 1.54 2004/10/15 22:40:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "access/htup.h" #include "access/xact.h" +#include "storage/buf.h" /* @@ -72,23 +73,23 @@ extern TransactionId RecentGlobalXmin; * Assumes heap tuple is valid. * Beware of multiple evaluations of snapshot argument. */ -#define HeapTupleSatisfiesVisibility(tuple, snapshot) \ +#define HeapTupleSatisfiesVisibility(tuple, snapshot, buffer) \ ((snapshot) == SnapshotNow ? \ - HeapTupleSatisfiesNow((tuple)->t_data) \ + HeapTupleSatisfiesNow((tuple)->t_data, buffer) \ : \ ((snapshot) == SnapshotSelf ? \ - HeapTupleSatisfiesItself((tuple)->t_data) \ + HeapTupleSatisfiesItself((tuple)->t_data, buffer) \ : \ ((snapshot) == SnapshotAny ? \ true \ : \ ((snapshot) == SnapshotToast ? \ - HeapTupleSatisfiesToast((tuple)->t_data) \ + HeapTupleSatisfiesToast((tuple)->t_data, buffer) \ : \ ((snapshot) == SnapshotDirty ? \ - HeapTupleSatisfiesDirty((tuple)->t_data) \ + HeapTupleSatisfiesDirty((tuple)->t_data, buffer) \ : \ - HeapTupleSatisfiesSnapshot((tuple)->t_data, snapshot) \ + HeapTupleSatisfiesSnapshot((tuple)->t_data, snapshot, buffer) \ ) \ ) \ ) \ @@ -108,21 +109,20 @@ typedef enum HEAPTUPLE_DEAD, /* tuple is dead and deletable */ HEAPTUPLE_LIVE, /* tuple is live (committed, no deleter) */ HEAPTUPLE_RECENTLY_DEAD, /* tuple is dead, but not deletable yet */ - HEAPTUPLE_INSERT_IN_PROGRESS, /* inserting xact is still in - * progress */ + HEAPTUPLE_INSERT_IN_PROGRESS, /* inserting xact is still in progress */ HEAPTUPLE_DELETE_IN_PROGRESS /* deleting xact is still in progress */ } HTSV_Result; -extern bool HeapTupleSatisfiesItself(HeapTupleHeader tuple); -extern bool HeapTupleSatisfiesNow(HeapTupleHeader tuple); -extern bool HeapTupleSatisfiesDirty(HeapTupleHeader tuple); -extern bool HeapTupleSatisfiesToast(HeapTupleHeader tuple); +extern bool HeapTupleSatisfiesItself(HeapTupleHeader tuple, Buffer buffer); +extern bool HeapTupleSatisfiesNow(HeapTupleHeader tuple, Buffer buffer); +extern bool HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Buffer buffer); +extern bool HeapTupleSatisfiesToast(HeapTupleHeader tuple, Buffer buffer); extern bool HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, - Snapshot snapshot); + Snapshot snapshot, Buffer buffer); extern int HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, - CommandId curcid); + CommandId curcid, Buffer buffer); extern HTSV_Result HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, - TransactionId OldestXmin); + TransactionId OldestXmin, Buffer buffer); extern Snapshot GetTransactionSnapshot(void); extern Snapshot GetLatestSnapshot(void); -- GitLab