Adjust HeapTupleSatisfies* routines to take a HeapTuple.
authorRobert Haas <rhaas@postgresql.org>
Mon, 22 Jul 2013 17:26:33 +0000 (13:26 -0400)
committerRobert Haas <rhaas@postgresql.org>
Mon, 22 Jul 2013 17:38:44 +0000 (13:38 -0400)
Previously, these functions took a HeapTupleHeader, but upcoming
patches for logical replication will introduce new a new snapshot
type under which the tuple's TID will be used to lookup (CMIN, CMAX)
for visibility determination purposes.  This makes that information
available.  Code churn is minimal since HeapTupleSatisfiesVisibility
took the HeapTuple anyway, and deferenced it before calling the
satisfies function.

Independently of logical replication, this allows t_tableOid and
t_self to be cross-checked via assertions in tqual.c.  This seems
like a useful way to make sure that all callers are setting these
values properly, which has been previously put forward as
desirable.

Andres Freund, reviewed by Álvaro Herrera

12 files changed:
contrib/pgrowlocks/pgrowlocks.c
src/backend/access/heap/heapam.c
src/backend/access/heap/pruneheap.c
src/backend/catalog/index.c
src/backend/commands/analyze.c
src/backend/commands/cluster.c
src/backend/commands/vacuumlazy.c
src/backend/executor/nodeBitmapHeapscan.c
src/backend/storage/lmgr/predicate.c
src/backend/utils/time/tqual.c
src/include/utils/snapshot.h
src/include/utils/tqual.h

index 075d78131a017b88f6ab4ae8439466dbfdbbe23d..8d8e78ea4aa8fa0ea4eb588a97563dd568ca978b 100644 (file)
@@ -131,7 +131,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
        /* must hold a buffer lock to call HeapTupleSatisfiesUpdate */
        LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
 
-       htsu = HeapTupleSatisfiesUpdate(tuple->t_data,
+       htsu = HeapTupleSatisfiesUpdate(tuple,
                                        GetCurrentCommandId(false),
                                        scan->rs_cbuf);
        xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
index 5bcbc92bfa4a0d68b8b57bfc1a61cdc2de0da920..b1a5d9f65ac055e0c2dd9807ad8477b70a70f3c6 100644 (file)
@@ -387,6 +387,7 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
            HeapTupleData loctup;
            bool        valid;
 
+           loctup.t_tableOid = RelationGetRelid(scan->rs_rd);
            loctup.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
            loctup.t_len = ItemIdGetLength(lpp);
            ItemPointerSet(&(loctup.t_self), page, lineoff);
@@ -1715,7 +1716,7 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
 
        heapTuple->t_data = (HeapTupleHeader) PageGetItem(dp, lp);
        heapTuple->t_len = ItemIdGetLength(lp);
-       heapTuple->t_tableOid = relation->rd_id;
+       heapTuple->t_tableOid = RelationGetRelid(relation);
        heapTuple->t_self = *tid;
 
        /*
@@ -1763,7 +1764,7 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
         * transactions.
         */
        if (all_dead && *all_dead &&
-           !HeapTupleIsSurelyDead(heapTuple->t_data, RecentGlobalXmin))
+           !HeapTupleIsSurelyDead(heapTuple, RecentGlobalXmin))
            *all_dead = false;
 
        /*
@@ -1893,6 +1894,7 @@ heap_get_latest_tid(Relation relation,
        tp.t_self = ctid;
        tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
        tp.t_len = ItemIdGetLength(lp);
+       tp.t_tableOid = RelationGetRelid(relation);
 
        /*
         * After following a t_ctid link, we might arrive at an unrelated
@@ -2591,12 +2593,13 @@ heap_delete(Relation relation, ItemPointer tid,
    lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
    Assert(ItemIdIsNormal(lp));
 
+   tp.t_tableOid = RelationGetRelid(relation);
    tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
    tp.t_len = ItemIdGetLength(lp);
    tp.t_self = *tid;
 
 l1:
-   result = HeapTupleSatisfiesUpdate(tp.t_data, cid, buffer);
+   result = HeapTupleSatisfiesUpdate(&tp, cid, buffer);
 
    if (result == HeapTupleInvisible)
    {
@@ -3070,7 +3073,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
 l2:
    checked_lockers = false;
    locker_remains = false;
-   result = HeapTupleSatisfiesUpdate(oldtup.t_data, cid, buffer);
+   result = HeapTupleSatisfiesUpdate(&oldtup, cid, buffer);
 
    /* see below about the "no wait" case */
    Assert(result != HeapTupleBeingUpdated || wait);
@@ -3941,7 +3944,7 @@ heap_lock_tuple(Relation relation, HeapTuple tuple,
    tuple->t_tableOid = RelationGetRelid(relation);
 
 l3:
-   result = HeapTupleSatisfiesUpdate(tuple->t_data, cid, *buffer);
+   result = HeapTupleSatisfiesUpdate(tuple, cid, *buffer);
 
    if (result == HeapTupleInvisible)
    {
index c6e31542935b79089f26dbde069d4a29b71421f6..3ec10a07c02cf2cff0419527f4ab45548470eef3 100644 (file)
@@ -339,6 +339,9 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
    OffsetNumber chainitems[MaxHeapTuplesPerPage];
    int         nchain = 0,
                i;
+   HeapTupleData tup;
+
+   tup.t_tableOid = RelationGetRelid(relation);
 
    rootlp = PageGetItemId(dp, rootoffnum);
 
@@ -348,6 +351,12 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
    if (ItemIdIsNormal(rootlp))
    {
        htup = (HeapTupleHeader) PageGetItem(dp, rootlp);
+
+       tup.t_data = htup;
+       tup.t_len = ItemIdGetLength(rootlp);
+       tup.t_tableOid = RelationGetRelid(relation);
+       ItemPointerSet(&(tup.t_self), BufferGetBlockNumber(buffer), rootoffnum);
+
        if (HeapTupleHeaderIsHeapOnly(htup))
        {
            /*
@@ -368,7 +377,7 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
             * either here or while following a chain below.  Whichever path
             * gets there first will mark the tuple unused.
             */
-           if (HeapTupleSatisfiesVacuum(htup, OldestXmin, buffer)
+           if (HeapTupleSatisfiesVacuum(&tup, OldestXmin, buffer)
                == HEAPTUPLE_DEAD && !HeapTupleHeaderIsHotUpdated(htup))
            {
                heap_prune_record_unused(prstate, rootoffnum);
@@ -431,6 +440,10 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
        Assert(ItemIdIsNormal(lp));
        htup = (HeapTupleHeader) PageGetItem(dp, lp);
 
+       tup.t_data = htup;
+       tup.t_len = ItemIdGetLength(lp);
+       ItemPointerSet(&(tup.t_self), BufferGetBlockNumber(buffer), offnum);
+
        /*
         * Check the tuple XMIN against prior XMAX, if any
         */
@@ -448,7 +461,7 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
         */
        tupdead = recent_dead = false;
 
-       switch (HeapTupleSatisfiesVacuum(htup, OldestXmin, buffer))
+       switch (HeapTupleSatisfiesVacuum(&tup, OldestXmin, buffer))
        {
            case HEAPTUPLE_DEAD:
                tupdead = true;
index 8525cb9ec83877348647d01ff679ad8105ba192d..7e4d7c0578c668f4177008ecbadf1e2bf30597e5 100644 (file)
@@ -2251,7 +2251,7 @@ IndexBuildHeapScan(Relation heapRelation,
             */
            LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
 
-           switch (HeapTupleSatisfiesVacuum(heapTuple->t_data, OldestXmin,
+           switch (HeapTupleSatisfiesVacuum(heapTuple, OldestXmin,
                                             scan->rs_cbuf))
            {
                case HEAPTUPLE_DEAD:
index d6d20fde9af6813c4cc8ec1465eee02ad8670d99..9845b0b50af7649356a242471dd1a343d297b19c 100644 (file)
@@ -1138,10 +1138,11 @@ acquire_sample_rows(Relation onerel, int elevel,
 
            ItemPointerSet(&targtuple.t_self, targblock, targoffset);
 
+           targtuple.t_tableOid = RelationGetRelid(onerel);
            targtuple.t_data = (HeapTupleHeader) PageGetItem(targpage, itemid);
            targtuple.t_len = ItemIdGetLength(itemid);
 
-           switch (HeapTupleSatisfiesVacuum(targtuple.t_data,
+           switch (HeapTupleSatisfiesVacuum(&targtuple,
                                             OldestXmin,
                                             targbuffer))
            {
index c20a6fb073e04009392722948de2f17eb8917a49..4519c00e22363fa32b6097543c5fb03af7042621 100644 (file)
@@ -979,7 +979,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
 
        LockBuffer(buf, BUFFER_LOCK_SHARE);
 
-       switch (HeapTupleSatisfiesVacuum(tuple->t_data, OldestXmin, buf))
+       switch (HeapTupleSatisfiesVacuum(tuple, OldestXmin, buf))
        {
            case HEAPTUPLE_DEAD:
                /* Definitely dead */
index 078b822059ceb41e3f17f89a9d6934068cfd6a6f..c34aa53728110149e76bd43c8e4f814fdafa33d7 100644 (file)
@@ -151,7 +151,7 @@ static void lazy_record_dead_tuple(LVRelStats *vacrelstats,
                       ItemPointer itemptr);
 static bool lazy_tid_reaped(ItemPointer itemptr, void *state);
 static int vac_cmp_itemptr(const void *left, const void *right);
-static bool heap_page_is_all_visible(Buffer buf,
+static bool heap_page_is_all_visible(Relation rel, Buffer buf,
                         TransactionId *visibility_cutoff_xid);
 
 
@@ -756,10 +756,11 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
 
            tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
            tuple.t_len = ItemIdGetLength(itemid);
+           tuple.t_tableOid = RelationGetRelid(onerel);
 
            tupgone = false;
 
-           switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin, buf))
+           switch (HeapTupleSatisfiesVacuum(&tuple, OldestXmin, buf))
            {
                case HEAPTUPLE_DEAD:
 
@@ -1168,7 +1169,7 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
     * check if the page has become all-visible.
     */
    if (!visibilitymap_test(onerel, blkno, vmbuffer) &&
-       heap_page_is_all_visible(buffer, &visibility_cutoff_xid))
+       heap_page_is_all_visible(onerel, buffer, &visibility_cutoff_xid))
    {
        Assert(BufferIsValid(*vmbuffer));
        PageSetAllVisible(page);
@@ -1676,7 +1677,7 @@ vac_cmp_itemptr(const void *left, const void *right)
  * xmin amongst the visible tuples.
  */
 static bool
-heap_page_is_all_visible(Buffer buf, TransactionId *visibility_cutoff_xid)
+heap_page_is_all_visible(Relation rel, Buffer buf, TransactionId *visibility_cutoff_xid)
 {
    Page        page = BufferGetPage(buf);
    OffsetNumber offnum,
@@ -1718,8 +1719,10 @@ heap_page_is_all_visible(Buffer buf, TransactionId *visibility_cutoff_xid)
        Assert(ItemIdIsNormal(itemid));
 
        tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
+       tuple.t_len = ItemIdGetLength(itemid);
+       tuple.t_tableOid = RelationGetRelid(rel);
 
-       switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin, buf))
+       switch (HeapTupleSatisfiesVacuum(&tuple, OldestXmin, buf))
        {
            case HEAPTUPLE_LIVE:
                {
index bbb89e69962d305b9eb736efbdcd43ba0fca86aa..45292b26333655d717f3607ebc2781800bc87937 100644 (file)
@@ -258,6 +258,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
 
        scan->rs_ctup.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
        scan->rs_ctup.t_len = ItemIdGetLength(lp);
+       scan->rs_ctup.t_tableOid = scan->rs_rd->rd_id;
        ItemPointerSet(&scan->rs_ctup.t_self, tbmres->blockno, targoffset);
 
        pgstat_count_heap_fetch(scan->rs_rd);
index b012df1c5d9dc688d88eb3e09e7401a79ff37cd4..d656d6239819fb9ddf6fe083e96ff25c3beeeff4 100644 (file)
@@ -3895,7 +3895,7 @@ CheckForSerializableConflictOut(bool visible, Relation relation,
     * tuple is visible to us, while HeapTupleSatisfiesVacuum checks what else
     * is going on with it.
     */
-   htsvResult = HeapTupleSatisfiesVacuum(tuple->t_data, TransactionXmin, buffer);
+   htsvResult = HeapTupleSatisfiesVacuum(tuple, TransactionXmin, buffer);
    switch (htsvResult)
    {
        case HEAPTUPLE_LIVE:
index c69ffd306ed2cc6978857d77ef24292b26593ea1..da2ce1825e043cc5bd21a48f31bdd2438df659b5 100644 (file)
@@ -163,8 +163,12 @@ HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
  *          Xmax is not committed)))           that has not been committed
  */
 bool
-HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
+HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
 {
+   HeapTupleHeader tuple = htup->t_data;
+   Assert(ItemPointerIsValid(&htup->t_self));
+   Assert(htup->t_tableOid != InvalidOid);
+
    if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
    {
        if (tuple->t_infomask & HEAP_XMIN_INVALID)
@@ -351,8 +355,12 @@ HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
  *
  */
 bool
-HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
+HeapTupleSatisfiesNow(HeapTuple htup, Snapshot snapshot, Buffer buffer)
 {
+   HeapTupleHeader tuple = htup->t_data;
+   Assert(ItemPointerIsValid(&htup->t_self));
+   Assert(htup->t_tableOid != InvalidOid);
+
    if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
    {
        if (tuple->t_infomask & HEAP_XMIN_INVALID)
@@ -526,7 +534,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
  *     Dummy "satisfies" routine: any tuple satisfies SnapshotAny.
  */
 bool
-HeapTupleSatisfiesAny(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
+HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer)
 {
    return true;
 }
@@ -546,9 +554,13 @@ HeapTupleSatisfiesAny(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
  * table.
  */
 bool
-HeapTupleSatisfiesToast(HeapTupleHeader tuple, Snapshot snapshot,
+HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot,
                        Buffer buffer)
 {
+   HeapTupleHeader tuple = htup->t_data;
+   Assert(ItemPointerIsValid(&htup->t_self));
+   Assert(htup->t_tableOid != InvalidOid);
+
    if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
    {
        if (tuple->t_infomask & HEAP_XMIN_INVALID)
@@ -627,9 +639,13 @@ HeapTupleSatisfiesToast(HeapTupleHeader tuple, Snapshot snapshot,
  * distinguish that case must test for it themselves.)
  */
 HTSU_Result
-HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
+HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
                         Buffer buffer)
 {
+   HeapTupleHeader tuple = htup->t_data;
+   Assert(ItemPointerIsValid(&htup->t_self));
+   Assert(htup->t_tableOid != InvalidOid);
+
    if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
    {
        if (tuple->t_infomask & HEAP_XMIN_INVALID)
@@ -849,9 +865,13 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
  * for snapshot->xmax and the tuple's xmax.
  */
 bool
-HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
+HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
                        Buffer buffer)
 {
+   HeapTupleHeader tuple = htup->t_data;
+   Assert(ItemPointerIsValid(&htup->t_self));
+   Assert(htup->t_tableOid != InvalidOid);
+
    snapshot->xmin = snapshot->xmax = InvalidTransactionId;
 
    if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
@@ -1040,9 +1060,13 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
  * can't see it.)
  */
 bool
-HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
+HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
                       Buffer buffer)
 {
+   HeapTupleHeader tuple = htup->t_data;
+   Assert(ItemPointerIsValid(&htup->t_self));
+   Assert(htup->t_tableOid != InvalidOid);
+
    if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
    {
        if (tuple->t_infomask & HEAP_XMIN_INVALID)
@@ -1233,9 +1257,13 @@ HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
  * even if we see that the deleting transaction has committed.
  */
 HTSV_Result
-HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
+HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin,
                         Buffer buffer)
 {
+   HeapTupleHeader tuple = htup->t_data;
+   Assert(ItemPointerIsValid(&htup->t_self));
+   Assert(htup->t_tableOid != InvalidOid);
+
    /*
     * Has inserting transaction committed?
     *
@@ -1466,8 +1494,12 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
  * just whether or not the tuple is surely dead).
  */
 bool
-HeapTupleIsSurelyDead(HeapTupleHeader tuple, TransactionId OldestXmin)
+HeapTupleIsSurelyDead(HeapTuple htup, TransactionId OldestXmin)
 {
+   HeapTupleHeader tuple = htup->t_data;
+   Assert(ItemPointerIsValid(&htup->t_self));
+   Assert(htup->t_tableOid != InvalidOid);
+
    /*
     * If the inserting transaction is marked invalid, then it aborted, and
     * the tuple is definitely dead.  If it's marked neither committed nor
index e747191e7932fd20fdbe8e6c0f0ac8e0d972ae1d..ed3f58692ea3da42afddc67884f855898fbd9c02 100644 (file)
@@ -27,8 +27,8 @@ typedef struct SnapshotData *Snapshot;
  * The specific semantics of a snapshot are encoded by the "satisfies"
  * function.
  */
-typedef bool (*SnapshotSatisfiesFunc) (HeapTupleHeader tuple,
-                                          Snapshot snapshot, Buffer buffer);
+typedef bool (*SnapshotSatisfiesFunc) (HeapTuple htup,
+                                      Snapshot snapshot, Buffer buffer);
 
 typedef struct SnapshotData
 {
index 465231c758459f950e491bd1300b8cfc23180a62..800e366f30b51d1fde19d53548fb09c0b0fb7a25 100644 (file)
@@ -52,7 +52,7 @@ extern PGDLLIMPORT SnapshotData SnapshotToastData;
  * if so, the indicated buffer is marked dirty.
  */
 #define HeapTupleSatisfiesVisibility(tuple, snapshot, buffer) \
-   ((*(snapshot)->satisfies) ((tuple)->t_data, snapshot, buffer))
+   ((*(snapshot)->satisfies) (tuple, snapshot, buffer))
 
 /* Result codes for HeapTupleSatisfiesVacuum */
 typedef enum
@@ -65,25 +65,25 @@ typedef enum
 } HTSV_Result;
 
 /* These are the "satisfies" test routines for the various snapshot types */
-extern bool HeapTupleSatisfiesMVCC(HeapTupleHeader tuple,
+extern bool HeapTupleSatisfiesMVCC(HeapTuple htup,
                       Snapshot snapshot, Buffer buffer);
-extern bool HeapTupleSatisfiesNow(HeapTupleHeader tuple,
+extern bool HeapTupleSatisfiesNow(HeapTuple htup,
                      Snapshot snapshot, Buffer buffer);
-extern bool HeapTupleSatisfiesSelf(HeapTupleHeader tuple,
+extern bool HeapTupleSatisfiesSelf(HeapTuple htup,
                       Snapshot snapshot, Buffer buffer);
-extern bool HeapTupleSatisfiesAny(HeapTupleHeader tuple,
+extern bool HeapTupleSatisfiesAny(HeapTuple htup,
                      Snapshot snapshot, Buffer buffer);
-extern bool HeapTupleSatisfiesToast(HeapTupleHeader tuple,
+extern bool HeapTupleSatisfiesToast(HeapTuple htup,
                        Snapshot snapshot, Buffer buffer);
-extern bool HeapTupleSatisfiesDirty(HeapTupleHeader tuple,
+extern bool HeapTupleSatisfiesDirty(HeapTuple htup,
                        Snapshot snapshot, Buffer buffer);
 
 /* Special "satisfies" routines with different APIs */
-extern HTSU_Result HeapTupleSatisfiesUpdate(HeapTupleHeader tuple,
+extern HTSU_Result HeapTupleSatisfiesUpdate(HeapTuple htup,
                         CommandId curcid, Buffer buffer);
-extern HTSV_Result HeapTupleSatisfiesVacuum(HeapTupleHeader tuple,
+extern HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup,
                         TransactionId OldestXmin, Buffer buffer);
-extern bool HeapTupleIsSurelyDead(HeapTupleHeader tuple,
+extern bool HeapTupleIsSurelyDead(HeapTuple htup,
                      TransactionId OldestXmin);
 
 extern void HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,