Repair possible failure to update hint bits back to disk, per
authorTom Lane
Fri, 15 Oct 2004 22:40:29 +0000 (22:40 +0000)
committerTom Lane
Fri, 15 Oct 2004 22:40:29 +0000 (22:40 +0000)
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.

13 files changed:
contrib/pgstattuple/pgstattuple.c
src/backend/access/heap/heapam.c
src/backend/access/index/indexam.c
src/backend/access/nbtree/nbtinsert.c
src/backend/catalog/index.c
src/backend/commands/vacuum.c
src/backend/commands/vacuumlazy.c
src/backend/storage/buffer/bufmgr.c
src/backend/utils/adt/ri_triggers.c
src/backend/utils/time/tqual.c
src/include/access/valid.h
src/include/storage/bufmgr.h
src/include/utils/tqual.h

index bfe37eb9ed6975b4ae8eb208da84561741958cfc..e2fab7863eb4ef8ed05d08695380552395cec858 100644 (file)
@@ -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++;
        }
index b9a6072c799835424d4e8a45ad11e92060c874f7..af5325ea632a82e198ba5c8253b88d089e72bf1f 100644 (file)
@@ -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;
 
        /*
index 7c698fb48a25edaf1af6443b9035fccfd84b9000..214f646276bf30a50dc1d3c3547ed2cfd011afaa 100644 (file)
@@ -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);
    }
 
index 815e207fb2f504d428196cc5203921ec9e87c16f..32615a62c27a3250805b7fb677f51c62ed3ddef1 100644 (file)
@@ -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);
                }
index 8fb2f8f4f222c44185ae6ea9c2b2702f3bcbb7c5..19fc60b6c8898bfcd7f76ab54841f8c8646b3b93 100644 (file)
@@ -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)
index 232ec9a89e69c11fdc17153234d840e2e15950a8..3d0c6e0e996d65bf04cf069cd7c1b013d02549f9 100644 (file)
@@ -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;
index ebdb27f336f299205aa64cc397a4bc0049979b31..62ba05f9698dc15c437238df675e6553ef6d8852 100644 (file)
@@ -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)
index b98193ad38c74ddd5adf7de0f89a4a35d38e3215..a0f2bf9c117f981aa01fd779bb57a8299502d41d 100644 (file)
@@ -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... */
index 20ad56c31f1b18aa8e19c2c20f50ceee7a4f25ff..b195e243393fcf09cf5efc02f9b609d8b9c496ee 100644 (file)
@@ -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);
index 3adab87ace4c6be7ac4ac5ecd5417b2a5d35a5cb..f36e2c13b6c1a2d1c83911a1ae517ee97a97b88b 100644 (file)
@@ -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 */
index 785ae80b2433a2c0a901155fed5f226cc4bb9e11..62a547a181a38eeb290fa496baa53d84be49724e 100644 (file)
@@ -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 */
index cb8feda8bdf306e0ee387eca68714529d8c619bb..04bc09e22c69707301f4688205a5981ae46728b1 100644 (file)
@@ -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) \
-   ) \
 )
 
 /*
index 0854fa793a1a164d4ad007079850dc739be5babe..8aa6ed2c678f012f18f7fe9bbb09545ce85bab2d 100644 (file)
@@ -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);