Remove dependency on HeapTuple from predicate locking functions.
authorThomas Munro <tmunro@postgresql.org>
Tue, 28 Jan 2020 00:13:04 +0000 (13:13 +1300)
committerThomas Munro <tmunro@postgresql.org>
Tue, 28 Jan 2020 00:13:04 +0000 (13:13 +1300)
The following changes make the predicate locking functions more
generic and suitable for use by future access methods:

- PredicateLockTuple() is renamed to PredicateLockTID().  It takes
  ItemPointer and inserting transaction ID instead of HeapTuple.

- CheckForSerializableConflictIn() takes blocknum instead of buffer.

- CheckForSerializableConflictOut() no longer takes HeapTuple or buffer.

Author: Ashwin Agrawal
Reviewed-by: Andres Freund, Kuntal Ghosh, Thomas Munro
Discussion: https://postgr.es/m/CALfoeiv0k3hkEb3Oqk%3DziWqtyk2Jys1UOK5hwRBNeANT_yX%2Bng%40mail.gmail.com

12 files changed:
src/backend/access/gin/ginbtree.c
src/backend/access/gin/ginfast.c
src/backend/access/gin/gininsert.c
src/backend/access/gist/gist.c
src/backend/access/hash/hashinsert.c
src/backend/access/heap/heapam.c
src/backend/access/heap/heapam_handler.c
src/backend/access/index/indexam.c
src/backend/access/nbtree/nbtinsert.c
src/backend/storage/lmgr/predicate.c
src/include/access/heapam.h
src/include/storage/predicate.h

index 423e4acb83ec25304fbe4fb092d4d305552fc127..8d08b05f5156ec08302ffac211a0ec028c88a722 100644 (file)
@@ -89,7 +89,7 @@ ginFindLeafPage(GinBtree btree, bool searchMode,
        stack->predictNumber = 1;
 
        if (rootConflictCheck)
-               CheckForSerializableConflictIn(btree->index, NULL, stack->buffer);
+               CheckForSerializableConflictIn(btree->index, NULL, btree->rootBlkno);
 
        for (;;)
        {
index 439055eac9d4d153104c3c9beba4c1b953f7754c..11d7ec067a0ca238e5c81cbb7d94768642f0f5a7 100644 (file)
@@ -246,7 +246,7 @@ ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
         * tree, so it conflicts with all serializable scans.  All scans acquire a
         * predicate lock on the metabuffer to represent that.
         */
-       CheckForSerializableConflictIn(index, NULL, metabuffer);
+       CheckForSerializableConflictIn(index, NULL, GIN_METAPAGE_BLKNO);
 
        if (collector->sumsize + collector->ntuples * sizeof(ItemIdData) > GinListPageSize)
        {
index 351a8813f968c1b0c4eb141dcf6754f12b648961..77433dc8a41e79a030bf7303dcf30376ce874f5e 100644 (file)
@@ -216,7 +216,8 @@ ginEntryInsert(GinState *ginstate,
                        return;
                }
 
-               CheckForSerializableConflictIn(ginstate->index, NULL, stack->buffer);
+               CheckForSerializableConflictIn(ginstate->index, NULL,
+                                                                          BufferGetBlockNumber(stack->buffer));
                /* modify an existing leaf entry */
                itup = addItemPointersToLeafTuple(ginstate, itup,
                                                                                  items, nitem, buildStats, stack->buffer);
@@ -225,7 +226,8 @@ ginEntryInsert(GinState *ginstate,
        }
        else
        {
-               CheckForSerializableConflictIn(ginstate->index, NULL, stack->buffer);
+               CheckForSerializableConflictIn(ginstate->index, NULL,
+                                                                          BufferGetBlockNumber(stack->buffer));
                /* no match, so construct a new leaf entry */
                itup = buildFreshLeafTuple(ginstate, attnum, key, category,
                                                                   items, nitem, buildStats, stack->buffer);
index aefc302ed297fb1fbf53f56fc89d9b7202ed409f..90c46e86a19cf52a61e64259a3520dbf66c0a35a 100644 (file)
@@ -1264,7 +1264,7 @@ gistinserttuples(GISTInsertState *state, GISTInsertStack *stack,
         * Check for any rw conflicts (in serializable isolation level) just
         * before we intend to modify the page
         */
-       CheckForSerializableConflictIn(state->r, NULL, stack->buffer);
+       CheckForSerializableConflictIn(state->r, NULL, BufferGetBlockNumber(stack->buffer));
 
        /* Insert the tuple(s) to the page, splitting the page if necessary */
        is_split = gistplacetopage(state->r, state->freespace, giststate,
index 32078274d28c8c21b166fd10efcd72ba36c475ce..2ebe671967ba2aeb7db961233fbb7ed2a07b1cef 100644 (file)
@@ -88,7 +88,7 @@ restart_insert:
                                                                                  &usedmetap);
        Assert(usedmetap != NULL);
 
-       CheckForSerializableConflictIn(rel, NULL, buf);
+       CheckForSerializableConflictIn(rel, NULL, BufferGetBlockNumber(buf));
 
        /* remember the primary bucket buffer to release the pin on it at end. */
        bucket_buf = buf;
index 5ddb6e85e97b21f155a422dac5465810c28942ad..ef7b472381fd989a91ae5da3bd8f806154cd7398 100644 (file)
@@ -41,6 +41,7 @@
 #include "access/multixact.h"
 #include "access/parallel.h"
 #include "access/relscan.h"
+#include "access/subtrans.h"
 #include "access/sysattr.h"
 #include "access/tableam.h"
 #include "access/transam.h"
@@ -446,8 +447,8 @@ heapgetpage(TableScanDesc sscan, BlockNumber page)
                        else
                                valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);
 
-                       CheckForSerializableConflictOut(valid, scan->rs_base.rs_rd,
-                                                                                       &loctup, buffer, snapshot);
+                       HeapCheckForSerializableConflictOut(valid, scan->rs_base.rs_rd,
+                                                                                               &loctup, buffer, snapshot);
 
                        if (valid)
                                scan->rs_vistuples[ntup++] = lineoff;
@@ -668,9 +669,9 @@ heapgettup(HeapScanDesc scan,
                                                                                                         snapshot,
                                                                                                         scan->rs_cbuf);
 
-                               CheckForSerializableConflictOut(valid, scan->rs_base.rs_rd,
-                                                                                               tuple, scan->rs_cbuf,
-                                                                                               snapshot);
+                               HeapCheckForSerializableConflictOut(valid, scan->rs_base.rs_rd,
+                                                                                                       tuple, scan->rs_cbuf,
+                                                                                                       snapshot);
 
                                if (valid && key != NULL)
                                        HeapKeyTest(tuple, RelationGetDescr(scan->rs_base.rs_rd),
@@ -1477,9 +1478,10 @@ heap_fetch(Relation relation,
        valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer);
 
        if (valid)
-               PredicateLockTuple(relation, tuple, snapshot);
+               PredicateLockTID(relation, &(tuple->t_self), snapshot,
+                                                HeapTupleHeaderGetXmin(tuple->t_data));
 
-       CheckForSerializableConflictOut(valid, relation, tuple, buffer, snapshot);
+       HeapCheckForSerializableConflictOut(valid, relation, tuple, buffer, snapshot);
 
        LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 
@@ -1610,13 +1612,14 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
                {
                        /* If it's visible per the snapshot, we must return it */
                        valid = HeapTupleSatisfiesVisibility(heapTuple, snapshot, buffer);
-                       CheckForSerializableConflictOut(valid, relation, heapTuple,
-                                                                                       buffer, snapshot);
+                       HeapCheckForSerializableConflictOut(valid, relation, heapTuple,
+                                                                                               buffer, snapshot);
 
                        if (valid)
                        {
                                ItemPointerSetOffsetNumber(tid, offnum);
-                               PredicateLockTuple(relation, heapTuple, snapshot);
+                               PredicateLockTID(relation, &heapTuple->t_self, snapshot,
+                                                                HeapTupleHeaderGetXmin(heapTuple->t_data));
                                if (all_dead)
                                        *all_dead = false;
                                return true;
@@ -1750,7 +1753,7 @@ heap_get_latest_tid(TableScanDesc sscan,
                 * candidate.
                 */
                valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer);
-               CheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot);
+               HeapCheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot);
                if (valid)
                        *tid = ctid;
 
@@ -1905,7 +1908,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
         * lock "gaps" as index page locks do.  So we don't need to specify a
         * buffer when making the call, which makes for a faster check.
         */
-       CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
+       CheckForSerializableConflictIn(relation, NULL, InvalidBlockNumber);
 
        /* NO EREPORT(ERROR) from here till changes are logged */
        START_CRIT_SECTION();
@@ -2159,7 +2162,7 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
         * lock "gaps" as index page locks do.  So we don't need to specify a
         * buffer when making the call, which makes for a faster check.
         */
-       CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
+       CheckForSerializableConflictIn(relation, NULL, InvalidBlockNumber);
 
        ndone = 0;
        while (ndone < ntuples)
@@ -2350,7 +2353,7 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
         * lock "gaps" as index page locks do.  So we don't need to specify a
         * buffer when making the call.
         */
-       CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
+       CheckForSerializableConflictIn(relation, NULL, InvalidBlockNumber);
 
        /*
         * If tuples are cachable, mark them for invalidation from the caches in
@@ -2664,7 +2667,7 @@ l1:
         * being visible to the scan (i.e., an exclusive buffer content lock is
         * continuously held from this point until the tuple delete is visible).
         */
-       CheckForSerializableConflictIn(relation, &tp, buffer);
+       CheckForSerializableConflictIn(relation, tid, BufferGetBlockNumber(buffer));
 
        /* replace cid with a combo cid if necessary */
        HeapTupleHeaderAdjustCmax(tp.t_data, &cid, &iscombo);
@@ -3580,7 +3583,7 @@ l2:
         * will include checking the relation level, there is no benefit to a
         * separate check for the new tuple.
         */
-       CheckForSerializableConflictIn(relation, &oldtup, buffer);
+       CheckForSerializableConflictIn(relation, otid, BufferGetBlockNumber(buffer));
 
        /*
         * At this point newbuf and buffer are both pinned and locked, and newbuf
@@ -9043,3 +9046,93 @@ heap_mask(char *pagedata, BlockNumber blkno)
                }
        }
 }
+
+/*
+ * HeapCheckForSerializableConflictOut
+ *             We are reading a tuple which has been modified.  If it is visible to
+ *             us but has been deleted, that indicates a rw-conflict out.  If it's
+ *             not visible and was created by a concurrent (overlapping)
+ *             serializable transaction, that is also a rw-conflict out,
+ *
+ * We will determine the top level xid of the writing transaction with which
+ * we may be in conflict, and check for overlap with our own transaction.
+ * If the transactions overlap (i.e., they cannot see each other's writes),
+ * then we have a conflict out.
+ *
+ * This function should be called just about anywhere in heapam.c where a
+ * tuple has been read. The caller must hold at least a shared lock on the
+ * buffer, because this function might set hint bits on the tuple. There is
+ * currently no known reason to call this function from an index AM.
+ */
+void
+HeapCheckForSerializableConflictOut(bool visible, Relation relation,
+                                                                       HeapTuple tuple, Buffer buffer,
+                                                                       Snapshot snapshot)
+{
+       TransactionId xid;
+       HTSV_Result htsvResult;
+
+       if (!CheckForSerializableConflictOutNeeded(relation, snapshot))
+               return;
+
+       /*
+        * Check to see whether the tuple has been written to by a concurrent
+        * transaction, either to create it not visible to us, or to delete it
+        * while it is visible to us.  The "visible" bool indicates whether the
+        * tuple is visible to us, while HeapTupleSatisfiesVacuum checks what else
+        * is going on with it.
+        */
+       htsvResult = HeapTupleSatisfiesVacuum(tuple, TransactionXmin, buffer);
+       switch (htsvResult)
+       {
+               case HEAPTUPLE_LIVE:
+                       if (visible)
+                               return;
+                       xid = HeapTupleHeaderGetXmin(tuple->t_data);
+                       break;
+               case HEAPTUPLE_RECENTLY_DEAD:
+                       if (!visible)
+                               return;
+                       xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
+                       break;
+               case HEAPTUPLE_DELETE_IN_PROGRESS:
+                       xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
+                       break;
+               case HEAPTUPLE_INSERT_IN_PROGRESS:
+                       xid = HeapTupleHeaderGetXmin(tuple->t_data);
+                       break;
+               case HEAPTUPLE_DEAD:
+                       return;
+               default:
+
+                       /*
+                        * The only way to get to this default clause is if a new value is
+                        * added to the enum type without adding it to this switch
+                        * statement.  That's a bug, so elog.
+                        */
+                       elog(ERROR, "unrecognized return value from HeapTupleSatisfiesVacuum: %u", htsvResult);
+
+                       /*
+                        * In spite of having all enum values covered and calling elog on
+                        * this default, some compilers think this is a code path which
+                        * allows xid to be used below without initialization. Silence
+                        * that warning.
+                        */
+                       xid = InvalidTransactionId;
+       }
+
+       Assert(TransactionIdIsValid(xid));
+       Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));
+
+       /*
+        * Find top level xid.  Bail out if xid is too early to be a conflict, or
+        * if it's our own xid.
+        */
+       if (TransactionIdEquals(xid, GetTopTransactionIdIfAny()))
+               return;
+       xid = SubTransGetTopmostTransaction(xid);
+       if (TransactionIdPrecedes(xid, TransactionXmin))
+               return;
+
+       return CheckForSerializableConflictOut(relation, xid, snapshot);
+}
index 1f6f6d0ea9eea253c8b6f2040d2b3b8351d26f1f..3fa4b766db885ce1edb956404a81dbb306977758 100644 (file)
@@ -2171,10 +2171,11 @@ heapam_scan_bitmap_next_block(TableScanDesc scan,
                        if (valid)
                        {
                                hscan->rs_vistuples[ntup++] = offnum;
-                               PredicateLockTuple(scan->rs_rd, &loctup, snapshot);
+                               PredicateLockTID(scan->rs_rd, &loctup.t_self, snapshot,
+                                                                HeapTupleHeaderGetXmin(loctup.t_data));
                        }
-                       CheckForSerializableConflictOut(valid, scan->rs_rd, &loctup,
-                                                                                       buffer, snapshot);
+                       HeapCheckForSerializableConflictOut(valid, scan->rs_rd, &loctup,
+                                                                                               buffer, snapshot);
                }
        }
 
@@ -2361,8 +2362,8 @@ heapam_scan_sample_next_tuple(TableScanDesc scan, SampleScanState *scanstate,
 
                        /* in pagemode, heapgetpage did this for us */
                        if (!pagemode)
-                               CheckForSerializableConflictOut(visible, scan->rs_rd, tuple,
-                                                                                               hscan->rs_cbuf, scan->rs_snapshot);
+                               HeapCheckForSerializableConflictOut(visible, scan->rs_rd, tuple,
+                                                                                                       hscan->rs_cbuf, scan->rs_snapshot);
 
                        /* Try next tuple from same page. */
                        if (!visible)
index 01539b6bd65cb635023ccd548fc9cb82b684c333..a5210d0b342e58c9c394ff9166ef38bcf22b8acd 100644 (file)
@@ -180,8 +180,8 @@ index_insert(Relation indexRelation,
 
        if (!(indexRelation->rd_indam->ampredlocks))
                CheckForSerializableConflictIn(indexRelation,
-                                                                          (HeapTuple) NULL,
-                                                                          InvalidBuffer);
+                                                                          (ItemPointer) NULL,
+                                                                          InvalidBlockNumber);
 
        return indexRelation->rd_indam->aminsert(indexRelation, values, isnull,
                                                                                         heap_t_ctid, heapRelation,
index 7ddba3ff9ff2a17dcc41e766d6da6ed012c80a6a..4e5849ab8e212907d38903c1dd1165cece73e373 100644 (file)
@@ -285,7 +285,7 @@ top:
                 * checkingunique and !heapkeyspace cases, but it's okay to use the
                 * first page the value could be on (with scantid omitted) instead.
                 */
-               CheckForSerializableConflictIn(rel, NULL, insertstate.buf);
+               CheckForSerializableConflictIn(rel, NULL, BufferGetBlockNumber(insertstate.buf));
 
                /*
                 * Do the insertion.  Note that insertstate contains cached binary
@@ -528,7 +528,7 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel,
                                         * otherwise be masked by this unique constraint
                                         * violation.
                                         */
-                                       CheckForSerializableConflictIn(rel, NULL, insertstate->buf);
+                                       CheckForSerializableConflictIn(rel, NULL, BufferGetBlockNumber(insertstate->buf));
 
                                        /*
                                         * This is a definite conflict.  Break the tuple down into
index de46b841cb32e656d1f987a7991e808ab8daf32f..654584b77af2564ab751620aa0442a5758c398d9 100644 (file)
  *             PredicateLockRelation(Relation relation, Snapshot snapshot)
  *             PredicateLockPage(Relation relation, BlockNumber blkno,
  *                                             Snapshot snapshot)
- *             PredicateLockTuple(Relation relation, HeapTuple tuple,
- *                                             Snapshot snapshot)
+ *             PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot,
+ *                                              TransactionId insert_xid)
  *             PredicateLockPageSplit(Relation relation, BlockNumber oldblkno,
  *                                                        BlockNumber newblkno)
  *             PredicateLockPageCombine(Relation relation, BlockNumber oldblkno,
  *             ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
  *
  * conflict detection (may also trigger rollback)
- *             CheckForSerializableConflictOut(bool visible, Relation relation,
- *                                                                             HeapTupleData *tup, Buffer buffer,
+ *             CheckForSerializableConflictOut(Relation relation, TransactionId xid,
  *                                                                             Snapshot snapshot)
- *             CheckForSerializableConflictIn(Relation relation, HeapTupleData *tup,
- *                                                                        Buffer buffer)
+ *             CheckForSerializableConflictIn(Relation relation, ItemPointer tid,
+ *                                                                        BlockNumber blkno)
  *             CheckTableForSerializableConflictIn(Relation relation)
  *
  * final rollback checking
 
 #include "postgres.h"
 
-#include "access/heapam.h"
-#include "access/htup_details.h"
 #include "access/parallel.h"
 #include "access/slru.h"
 #include "access/subtrans.h"
@@ -2538,28 +2535,28 @@ PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
 }
 
 /*
- *             PredicateLockTuple
+ *             PredicateLockTID
  *
  * Gets a predicate lock at the tuple level.
  * Skip if not in full serializable transaction isolation level.
  * Skip if this is a temporary table.
  */
 void
-PredicateLockTuple(Relation relation, HeapTuple tuple, Snapshot snapshot)
+PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot,
+                                TransactionId tuple_xid)
 {
        PREDICATELOCKTARGETTAG tag;
-       ItemPointer tid;
 
        if (!SerializationNeededForRead(relation, snapshot))
                return;
 
        /*
-        * If it's a heap tuple, return if this xact wrote it.
+        * Return if this xact wrote it.
         */
        if (relation->rd_index == NULL)
        {
                /* If we wrote it; we already have a write lock. */
-               if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple->t_data)))
+               if (TransactionIdIsCurrentTransactionId(tuple_xid))
                        return;
        }
 
@@ -2575,7 +2572,6 @@ PredicateLockTuple(Relation relation, HeapTuple tuple, Snapshot snapshot)
        if (PredicateLockExists(&tag))
                return;
 
-       tid = &(tuple->t_self);
        SET_PREDICATELOCKTARGETTAG_TUPLE(tag,
                                                                         relation->rd_node.dbNode,
                                                                         relation->rd_id,
@@ -4020,33 +4016,41 @@ XidIsConcurrent(TransactionId xid)
        return false;
 }
 
+bool
+CheckForSerializableConflictOutNeeded(Relation relation, Snapshot snapshot)
+{
+       if (!SerializationNeededForRead(relation, snapshot))
+               return false;
+
+       /* Check if someone else has already decided that we need to die */
+       if (SxactIsDoomed(MySerializableXact))
+       {
+               ereport(ERROR,
+                               (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+                                errmsg("could not serialize access due to read/write dependencies among transactions"),
+                                errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
+                                errhint("The transaction might succeed if retried.")));
+       }
+
+       return true;
+}
+
 /*
  * CheckForSerializableConflictOut
- *             We are reading a tuple which has been modified.  If it is visible to
- *             us but has been deleted, that indicates a rw-conflict out.  If it's
- *             not visible and was created by a concurrent (overlapping)
- *             serializable transaction, that is also a rw-conflict out,
+ *             A table AM is reading a tuple that has been modified.  After determining
+ *             that it is visible to us, it should call this function with the top
+ *             level xid of the writing transaction.
  *
- * We will determine the top level xid of the writing transaction with which
- * we may be in conflict, and check for overlap with our own transaction.
- * If the transactions overlap (i.e., they cannot see each other's writes),
- * then we have a conflict out.
- *
- * This function should be called just about anywhere in heapam.c where a
- * tuple has been read. The caller must hold at least a shared lock on the
- * buffer, because this function might set hint bits on the tuple. There is
- * currently no known reason to call this function from an index AM.
+ * This function will check for overlap with our own transaction.  If the
+ * transactions overlap (i.e., they cannot see each other's writes), then we
+ * have a conflict out.
  */
 void
-CheckForSerializableConflictOut(bool visible, Relation relation,
-                                                               HeapTuple tuple, Buffer buffer,
-                                                               Snapshot snapshot)
+CheckForSerializableConflictOut(Relation relation, TransactionId xid, Snapshot snapshot)
 {
-       TransactionId xid;
        SERIALIZABLEXIDTAG sxidtag;
        SERIALIZABLEXID *sxid;
        SERIALIZABLEXACT *sxact;
-       HTSV_Result htsvResult;
 
        if (!SerializationNeededForRead(relation, snapshot))
                return;
@@ -4060,64 +4064,8 @@ CheckForSerializableConflictOut(bool visible, Relation relation,
                                 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
                                 errhint("The transaction might succeed if retried.")));
        }
-
-       /*
-        * Check to see whether the tuple has been written to by a concurrent
-        * transaction, either to create it not visible to us, or to delete it
-        * while it is visible to us.  The "visible" bool indicates whether the
-        * tuple is visible to us, while HeapTupleSatisfiesVacuum checks what else
-        * is going on with it.
-        */
-       htsvResult = HeapTupleSatisfiesVacuum(tuple, TransactionXmin, buffer);
-       switch (htsvResult)
-       {
-               case HEAPTUPLE_LIVE:
-                       if (visible)
-                               return;
-                       xid = HeapTupleHeaderGetXmin(tuple->t_data);
-                       break;
-               case HEAPTUPLE_RECENTLY_DEAD:
-                       if (!visible)
-                               return;
-                       xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
-                       break;
-               case HEAPTUPLE_DELETE_IN_PROGRESS:
-                       xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
-                       break;
-               case HEAPTUPLE_INSERT_IN_PROGRESS:
-                       xid = HeapTupleHeaderGetXmin(tuple->t_data);
-                       break;
-               case HEAPTUPLE_DEAD:
-                       return;
-               default:
-
-                       /*
-                        * The only way to get to this default clause is if a new value is
-                        * added to the enum type without adding it to this switch
-                        * statement.  That's a bug, so elog.
-                        */
-                       elog(ERROR, "unrecognized return value from HeapTupleSatisfiesVacuum: %u", htsvResult);
-
-                       /*
-                        * In spite of having all enum values covered and calling elog on
-                        * this default, some compilers think this is a code path which
-                        * allows xid to be used below without initialization. Silence
-                        * that warning.
-                        */
-                       xid = InvalidTransactionId;
-       }
        Assert(TransactionIdIsValid(xid));
-       Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));
 
-       /*
-        * Find top level xid.  Bail out if xid is too early to be a conflict, or
-        * if it's our own xid.
-        */
-       if (TransactionIdEquals(xid, GetTopTransactionIdIfAny()))
-               return;
-       xid = SubTransGetTopmostTransaction(xid);
-       if (TransactionIdPrecedes(xid, TransactionXmin))
-               return;
        if (TransactionIdEquals(xid, GetTopTransactionIdIfAny()))
                return;
 
@@ -4423,8 +4371,7 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
  * tuple itself.
  */
 void
-CheckForSerializableConflictIn(Relation relation, HeapTuple tuple,
-                                                          Buffer buffer)
+CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
 {
        PREDICATELOCKTARGETTAG targettag;
 
@@ -4454,22 +4401,22 @@ CheckForSerializableConflictIn(Relation relation, HeapTuple tuple,
         * It is not possible to take and hold a lock across the checks for all
         * granularities because each target could be in a separate partition.
         */
-       if (tuple != NULL)
+       if (tid != NULL)
        {
                SET_PREDICATELOCKTARGETTAG_TUPLE(targettag,
                                                                                 relation->rd_node.dbNode,
                                                                                 relation->rd_id,
-                                                                                ItemPointerGetBlockNumber(&(tuple->t_self)),
-                                                                                ItemPointerGetOffsetNumber(&(tuple->t_self)));
+                                                                                ItemPointerGetBlockNumber(tid),
+                                                                                ItemPointerGetOffsetNumber(tid));
                CheckTargetForConflictsIn(&targettag);
        }
 
-       if (BufferIsValid(buffer))
+       if (blkno != InvalidBlockNumber)
        {
                SET_PREDICATELOCKTARGETTAG_PAGE(targettag,
                                                                                relation->rd_node.dbNode,
                                                                                relation->rd_id,
-                                                                               BufferGetBlockNumber(buffer));
+                                                                               blkno);
                CheckTargetForConflictsIn(&targettag);
        }
 
index 00a17f5f7179f14cfd306b27b1adf56084c0d7d4..47fda28daa147058634d5f84815c4af0307b4e14 100644 (file)
@@ -220,5 +220,7 @@ extern bool ResolveCminCmaxDuringDecoding(struct HTAB *tuplecid_data,
                                                                                  HeapTuple htup,
                                                                                  Buffer buffer,
                                                                                  CommandId *cmin, CommandId *cmax);
+extern void HeapCheckForSerializableConflictOut(bool valid, Relation relation, HeapTuple tuple,
+                                                                                               Buffer buffer, Snapshot snapshot);
 
 #endif                                                 /* HEAPAM_H */
index a6cc1a1bf0460224eefd341f9e794342ab548664..9df44ed0dc7d20f1f04c7fed6c7021a88681097e 100644 (file)
@@ -57,16 +57,17 @@ extern void SetSerializableTransactionSnapshot(Snapshot snapshot,
 extern void RegisterPredicateLockingXid(TransactionId xid);
 extern void PredicateLockRelation(Relation relation, Snapshot snapshot);
 extern void PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot);
-extern void PredicateLockTuple(Relation relation, HeapTuple tuple, Snapshot snapshot);
+extern void PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot,
+                                                        TransactionId insert_xid);
 extern void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno);
 extern void PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, BlockNumber newblkno);
 extern void TransferPredicateLocksToHeapRelation(Relation relation);
 extern void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe);
 
 /* conflict detection (may also trigger rollback) */
-extern void CheckForSerializableConflictOut(bool valid, Relation relation, HeapTuple tuple,
-                                                                                       Buffer buffer, Snapshot snapshot);
-extern void CheckForSerializableConflictIn(Relation relation, HeapTuple tuple, Buffer buffer);
+extern bool CheckForSerializableConflictOutNeeded(Relation relation, Snapshot snapshot);
+extern void CheckForSerializableConflictOut(Relation relation, TransactionId xid, Snapshot snapshot);
+extern void CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno);
 extern void CheckTableForSerializableConflictIn(Relation relation);
 
 /* final rollback checking */