*** a/src/backend/access/heap/heapam.c --- b/src/backend/access/heap/heapam.c *************** *** 274,280 **** heapgetpage(HeapScanDesc scan, BlockNumber page) else valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer); ! CheckForSerializableConflictOut(valid, scan->rs_rd, &loctup, buffer); if (valid) scan->rs_vistuples[ntup++] = lineoff; --- 274,280 ---- else valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer); ! CheckForSerializableConflictOut(valid, scan->rs_rd, &loctup, buffer, snapshot); if (valid) scan->rs_vistuples[ntup++] = lineoff; *************** *** 469,475 **** heapgettup(HeapScanDesc scan, snapshot, scan->rs_cbuf); ! CheckForSerializableConflictOut(valid, scan->rs_rd, tuple, scan->rs_cbuf); if (valid && key != NULL) HeapKeyTest(tuple, RelationGetDescr(scan->rs_rd), --- 469,475 ---- snapshot, scan->rs_cbuf); ! CheckForSerializableConflictOut(valid, scan->rs_rd, tuple, scan->rs_cbuf, snapshot); if (valid && key != NULL) HeapKeyTest(tuple, RelationGetDescr(scan->rs_rd), *************** *** 478,484 **** heapgettup(HeapScanDesc scan, if (valid) { if (!scan->rs_relpredicatelocked) ! PredicateLockTuple(scan->rs_rd, tuple); LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK); return; } --- 478,484 ---- if (valid) { if (!scan->rs_relpredicatelocked) ! PredicateLockTuple(scan->rs_rd, tuple, snapshot); LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK); return; } *************** *** 747,753 **** heapgettup_pagemode(HeapScanDesc scan, if (valid) { if (!scan->rs_relpredicatelocked) ! PredicateLockTuple(scan->rs_rd, tuple); scan->rs_cindex = lineindex; return; } --- 747,753 ---- if (valid) { if (!scan->rs_relpredicatelocked) ! PredicateLockTuple(scan->rs_rd, tuple, scan->rs_snapshot); scan->rs_cindex = lineindex; return; } *************** *** 755,761 **** heapgettup_pagemode(HeapScanDesc scan, else { if (!scan->rs_relpredicatelocked) ! PredicateLockTuple(scan->rs_rd, tuple); scan->rs_cindex = lineindex; return; } --- 755,761 ---- else { if (!scan->rs_relpredicatelocked) ! PredicateLockTuple(scan->rs_rd, tuple, scan->rs_snapshot); scan->rs_cindex = lineindex; return; } *************** *** 1470,1478 **** heap_fetch(Relation relation, valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer); if (valid) ! PredicateLockTuple(relation, tuple); ! CheckForSerializableConflictOut(valid, relation, tuple, buffer); LockBuffer(buffer, BUFFER_LOCK_UNLOCK); --- 1470,1478 ---- valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer); if (valid) ! PredicateLockTuple(relation, tuple, snapshot); ! CheckForSerializableConflictOut(valid, relation, tuple, buffer, snapshot); LockBuffer(buffer, BUFFER_LOCK_UNLOCK); *************** *** 1588,1598 **** 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); if (valid) { ItemPointerSetOffsetNumber(tid, offnum); ! PredicateLockTuple(relation, &heapTuple); if (all_dead) *all_dead = false; return true; --- 1588,1598 ---- /* If it's visible per the snapshot, we must return it */ valid = HeapTupleSatisfiesVisibility(&heapTuple, snapshot, buffer); ! CheckForSerializableConflictOut(valid, relation, &heapTuple, buffer, snapshot); if (valid) { ItemPointerSetOffsetNumber(tid, offnum); ! PredicateLockTuple(relation, &heapTuple, snapshot); if (all_dead) *all_dead = false; return true; *************** *** 1750,1756 **** heap_get_latest_tid(Relation relation, * result candidate. */ valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer); ! CheckForSerializableConflictOut(valid, relation, &tp, buffer); if (valid) *tid = ctid; --- 1750,1756 ---- * result candidate. */ valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer); ! CheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot); if (valid) *tid = ctid; *** a/src/backend/access/index/indexam.c --- b/src/backend/access/index/indexam.c *************** *** 126,132 **** do { \ } while(0) static IndexScanDesc index_beginscan_internal(Relation indexRelation, ! int nkeys, int norderbys); /* ---------------------------------------------------------------- --- 126,132 ---- } while(0) static IndexScanDesc index_beginscan_internal(Relation indexRelation, ! int nkeys, int norderbys, const Snapshot snapshot); /* ---------------------------------------------------------------- *************** *** 234,240 **** index_beginscan(Relation heapRelation, { IndexScanDesc scan; ! scan = index_beginscan_internal(indexRelation, nkeys, norderbys); /* * Save additional parameters into the scandesc. Everything else was set --- 234,240 ---- { IndexScanDesc scan; ! scan = index_beginscan_internal(indexRelation, nkeys, norderbys, snapshot); /* * Save additional parameters into the scandesc. Everything else was set *************** *** 259,265 **** index_beginscan_bitmap(Relation indexRelation, { IndexScanDesc scan; ! scan = index_beginscan_internal(indexRelation, nkeys, 0); /* * Save additional parameters into the scandesc. Everything else was set --- 259,265 ---- { IndexScanDesc scan; ! scan = index_beginscan_internal(indexRelation, nkeys, 0, snapshot); /* * Save additional parameters into the scandesc. Everything else was set *************** *** 275,281 **** index_beginscan_bitmap(Relation indexRelation, */ static IndexScanDesc index_beginscan_internal(Relation indexRelation, ! int nkeys, int norderbys) { IndexScanDesc scan; FmgrInfo *procedure; --- 275,281 ---- */ static IndexScanDesc index_beginscan_internal(Relation indexRelation, ! int nkeys, int norderbys, const Snapshot snapshot) { IndexScanDesc scan; FmgrInfo *procedure; *************** *** 284,290 **** index_beginscan_internal(Relation indexRelation, GET_REL_PROCEDURE(ambeginscan); if (!(indexRelation->rd_am->ampredlocks)) ! PredicateLockRelation(indexRelation); /* * We hold a reference count to the relcache entry throughout the scan. --- 284,290 ---- GET_REL_PROCEDURE(ambeginscan); if (!(indexRelation->rd_am->ampredlocks)) ! PredicateLockRelation(indexRelation, snapshot); /* * We hold a reference count to the relcache entry throughout the scan. *************** *** 602,608 **** index_getnext(IndexScanDesc scan, ScanDirection direction) scan->xs_cbuf); CheckForSerializableConflictOut(valid, scan->heapRelation, ! heapTuple, scan->xs_cbuf); if (valid) { --- 602,609 ---- scan->xs_cbuf); CheckForSerializableConflictOut(valid, scan->heapRelation, ! heapTuple, scan->xs_cbuf, ! scan->xs_snapshot); if (valid) { *************** *** 624,630 **** index_getnext(IndexScanDesc scan, ScanDirection direction) else scan->xs_next_hot = InvalidOffsetNumber; ! PredicateLockTuple(scan->heapRelation, heapTuple); LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK); --- 625,631 ---- else scan->xs_next_hot = InvalidOffsetNumber; ! PredicateLockTuple(scan->heapRelation, heapTuple, scan->xs_snapshot); LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK); *** a/src/backend/access/nbtree/nbtsearch.c --- b/src/backend/access/nbtree/nbtsearch.c *************** *** 65,71 **** _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey, /* If index is empty and access = BT_READ, no root page is created. */ if (!BufferIsValid(*bufP)) { ! PredicateLockRelation(rel); /* Nothing finer to lock exists. */ return (BTStack) NULL; } --- 65,71 ---- /* If index is empty and access = BT_READ, no root page is created. */ if (!BufferIsValid(*bufP)) { ! PredicateLockRelation(rel, NULL); /* Nothing finer to lock exists. */ return (BTStack) NULL; } *************** *** 94,100 **** _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey, if (P_ISLEAF(opaque)) { if (access == BT_READ) ! PredicateLockPage(rel, BufferGetBlockNumber(*bufP)); break; } --- 94,100 ---- if (P_ISLEAF(opaque)) { if (access == BT_READ) ! PredicateLockPage(rel, BufferGetBlockNumber(*bufP), NULL); break; } *************** *** 1153,1159 **** _bt_steppage(IndexScanDesc scan, ScanDirection dir) opaque = (BTPageOpaque) PageGetSpecialPointer(page); if (!P_IGNORE(opaque)) { ! PredicateLockPage(rel, blkno); /* see if there are any matches on this page */ /* note that this will clear moreRight if we can stop */ if (_bt_readpage(scan, dir, P_FIRSTDATAKEY(opaque))) --- 1153,1159 ---- opaque = (BTPageOpaque) PageGetSpecialPointer(page); if (!P_IGNORE(opaque)) { ! PredicateLockPage(rel, blkno, scan->xs_snapshot); /* see if there are any matches on this page */ /* note that this will clear moreRight if we can stop */ if (_bt_readpage(scan, dir, P_FIRSTDATAKEY(opaque))) *************** *** 1201,1207 **** _bt_steppage(IndexScanDesc scan, ScanDirection dir) opaque = (BTPageOpaque) PageGetSpecialPointer(page); if (!P_IGNORE(opaque)) { ! PredicateLockPage(rel, BufferGetBlockNumber(so->currPos.buf)); /* see if there are any matches on this page */ /* note that this will clear moreLeft if we can stop */ if (_bt_readpage(scan, dir, PageGetMaxOffsetNumber(page))) --- 1201,1207 ---- opaque = (BTPageOpaque) PageGetSpecialPointer(page); if (!P_IGNORE(opaque)) { ! PredicateLockPage(rel, BufferGetBlockNumber(so->currPos.buf), scan->xs_snapshot); /* see if there are any matches on this page */ /* note that this will clear moreLeft if we can stop */ if (_bt_readpage(scan, dir, PageGetMaxOffsetNumber(page))) *************** *** 1365,1371 **** _bt_get_endpoint(Relation rel, uint32 level, bool rightmost) if (!BufferIsValid(buf)) { /* empty index... */ ! PredicateLockRelation(rel); /* Nothing finer to lock exists. */ return InvalidBuffer; } --- 1365,1371 ---- if (!BufferIsValid(buf)) { /* empty index... */ ! PredicateLockRelation(rel, NULL); /* Nothing finer to lock exists. */ return InvalidBuffer; } *************** *** 1445,1456 **** _bt_endpoint(IndexScanDesc scan, ScanDirection dir) if (!BufferIsValid(buf)) { /* empty index... */ ! PredicateLockRelation(rel); /* Nothing finer to lock exists. */ so->currPos.buf = InvalidBuffer; return false; } ! PredicateLockPage(rel, BufferGetBlockNumber(buf)); page = BufferGetPage(buf); opaque = (BTPageOpaque) PageGetSpecialPointer(page); Assert(P_ISLEAF(opaque)); --- 1445,1456 ---- if (!BufferIsValid(buf)) { /* empty index... */ ! PredicateLockRelation(rel, scan->xs_snapshot); /* Nothing finer to lock exists. */ so->currPos.buf = InvalidBuffer; return false; } ! PredicateLockPage(rel, BufferGetBlockNumber(buf), scan->xs_snapshot); page = BufferGetPage(buf); opaque = (BTPageOpaque) PageGetSpecialPointer(page); Assert(P_ISLEAF(opaque)); *** a/src/backend/executor/nodeSeqscan.c --- b/src/backend/executor/nodeSeqscan.c *************** *** 113,119 **** SeqRecheck(SeqScanState *node, TupleTableSlot *slot) TupleTableSlot * ExecSeqScan(SeqScanState *node) { ! PredicateLockRelation(node->ss_currentRelation); node->ss_currentScanDesc->rs_relpredicatelocked = true; return ExecScan((ScanState *) node, (ExecScanAccessMtd) SeqNext, --- 113,120 ---- TupleTableSlot * ExecSeqScan(SeqScanState *node) { ! PredicateLockRelation(node->ss_currentRelation, ! node->ss_currentScanDesc->rs_snapshot); node->ss_currentScanDesc->rs_relpredicatelocked = true; return ExecScan((ScanState *) node, (ExecScanAccessMtd) SeqNext, *** a/src/backend/storage/lmgr/predicate.c --- b/src/backend/storage/lmgr/predicate.c *************** *** 148,156 **** * predicate lock maintenance * RegisterSerializableTransaction(Snapshot snapshot) * RegisterPredicateLockingXid(void) ! * PredicateLockRelation(Relation relation) ! * PredicateLockPage(Relation relation, BlockNumber blkno) ! * PredicateLockTuple(Relation relation, HeapTuple tuple) * PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, * BlockNumber newblkno); * PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, --- 148,158 ---- * predicate lock maintenance * RegisterSerializableTransaction(Snapshot snapshot) * RegisterPredicateLockingXid(void) ! * PredicateLockRelation(Relation relation, Snapshot snapshot) ! * PredicateLockPage(Relation relation, BlockNumber blkno, ! * Snapshot snapshot) ! * PredicateLockTuple(Relation relation, HeapTuple tuple, ! * Snapshot snapshot) * PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, * BlockNumber newblkno); * PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, *************** *** 160,166 **** * * conflict detection (may also trigger rollback) * CheckForSerializableConflictOut(bool visible, Relation relation, ! * HeapTupleData *tup, Buffer buffer) * CheckForSerializableConflictIn(Relation relation, HeapTupleData *tup, * Buffer buffer) * CheckTableForSerializableConflictIn(Relation relation) --- 162,169 ---- * * conflict detection (may also trigger rollback) * CheckForSerializableConflictOut(bool visible, Relation relation, ! * HeapTupleData *tup, Buffer buffer, ! * Snapshot snapshot) * CheckForSerializableConflictIn(Relation relation, HeapTupleData *tup, * Buffer buffer) * CheckTableForSerializableConflictIn(Relation relation) *************** *** 271,279 **** * the current transaction, this is the test to see if we should do a quick * return. */ ! #define SkipSerialization(relation) \ ((!IsolationIsSerializable()) \ || ((MySerializableXact == InvalidSerializableXact)) \ || ReleasePredicateLocksIfROSafe() \ || SkipPredicateLocksForRelation(relation)) --- 274,283 ---- * the current transaction, this is the test to see if we should do a quick * return. */ ! #define SkipSerialization(relation, snapshot) \ ((!IsolationIsSerializable()) \ || ((MySerializableXact == InvalidSerializableXact)) \ + || ((snapshot) != NULL && !IsMVCCSnapshot(snapshot)) \ || ReleasePredicateLocksIfROSafe() \ || SkipPredicateLocksForRelation(relation)) *************** *** 2201,2211 **** PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag) * Clear any finer-grained predicate locks this session has on the relation. */ void ! PredicateLockRelation(const Relation relation) { PREDICATELOCKTARGETTAG tag; ! if (SkipSerialization(relation)) return; SET_PREDICATELOCKTARGETTAG_RELATION(tag, --- 2205,2215 ---- * Clear any finer-grained predicate locks this session has on the relation. */ void ! PredicateLockRelation(const Relation relation, const Snapshot snapshot) { PREDICATELOCKTARGETTAG tag; ! if (SkipSerialization(relation, snapshot)) return; SET_PREDICATELOCKTARGETTAG_RELATION(tag, *************** *** 2224,2234 **** PredicateLockRelation(const Relation relation) * Clear any finer-grained predicate locks this session has on the relation. */ void ! PredicateLockPage(const Relation relation, const BlockNumber blkno) { PREDICATELOCKTARGETTAG tag; ! if (SkipSerialization(relation)) return; SET_PREDICATELOCKTARGETTAG_PAGE(tag, --- 2228,2239 ---- * Clear any finer-grained predicate locks this session has on the relation. */ void ! PredicateLockPage(const Relation relation, const BlockNumber blkno, ! const Snapshot snapshot) { PREDICATELOCKTARGETTAG tag; ! if (SkipSerialization(relation, snapshot)) return; SET_PREDICATELOCKTARGETTAG_PAGE(tag, *************** *** 2246,2258 **** PredicateLockPage(const Relation relation, const BlockNumber blkno) * Skip if this is a temporary table. */ void ! PredicateLockTuple(const Relation relation, const HeapTuple tuple) { PREDICATELOCKTARGETTAG tag; ItemPointer tid; TransactionId targetxmin; ! if (SkipSerialization(relation)) return; /* --- 2251,2264 ---- * Skip if this is a temporary table. */ void ! PredicateLockTuple(const Relation relation, const HeapTuple tuple, ! const Snapshot snapshot) { PREDICATELOCKTARGETTAG tag; ItemPointer tid; TransactionId targetxmin; ! if (SkipSerialization(relation, snapshot)) return; /* *************** *** 3613,3619 **** XidIsConcurrent(TransactionId xid) */ void CheckForSerializableConflictOut(const bool visible, const Relation relation, ! const HeapTuple tuple, const Buffer buffer) { TransactionId xid; SERIALIZABLEXIDTAG sxidtag; --- 3619,3626 ---- */ void CheckForSerializableConflictOut(const bool visible, const Relation relation, ! const HeapTuple tuple, const Buffer buffer, ! const Snapshot snapshot) { TransactionId xid; SERIALIZABLEXIDTAG sxidtag; *************** *** 3621,3627 **** CheckForSerializableConflictOut(const bool visible, const Relation relation, SERIALIZABLEXACT *sxact; HTSV_Result htsvResult; ! if (SkipSerialization(relation)) return; if (SxactIsMarkedForDeath(MySerializableXact)) --- 3628,3634 ---- SERIALIZABLEXACT *sxact; HTSV_Result htsvResult; ! if (SkipSerialization(relation, snapshot)) return; if (SxactIsMarkedForDeath(MySerializableXact)) *************** *** 3998,4004 **** CheckForSerializableConflictIn(const Relation relation, const HeapTuple tuple, { PREDICATELOCKTARGETTAG targettag; ! if (SkipSerialization(relation)) return; if (SxactIsMarkedForDeath(MySerializableXact)) --- 4005,4011 ---- { PREDICATELOCKTARGETTAG targettag; ! if (SkipSerialization(relation, (Snapshot) NULL)) return; if (SxactIsMarkedForDeath(MySerializableXact)) *************** *** 4090,4096 **** CheckTableForSerializableConflictIn(const Relation relation) if (!TransactionIdIsValid(PredXact->SxactGlobalXmin)) return; ! if (SkipSerialization(relation)) return; Assert(relation->rd_index == NULL); /* not an index relation */ --- 4097,4103 ---- if (!TransactionIdIsValid(PredXact->SxactGlobalXmin)) return; ! if (SkipSerialization(relation, (Snapshot) NULL)) return; Assert(relation->rd_index == NULL); /* not an index relation */ *** a/src/include/storage/predicate.h --- b/src/include/storage/predicate.h *************** *** 44,59 **** extern bool PageIsPredicateLocked(const Relation relation, const BlockNumber blk /* predicate lock maintenance */ extern Snapshot RegisterSerializableTransaction(Snapshot snapshot); extern void RegisterPredicateLockingXid(const TransactionId xid); ! extern void PredicateLockRelation(const Relation relation); ! extern void PredicateLockPage(const Relation relation, const BlockNumber blkno); ! extern void PredicateLockTuple(const Relation relation, const HeapTuple tuple); extern void PredicateLockPageSplit(const Relation relation, const BlockNumber oldblkno, const BlockNumber newblkno); extern void PredicateLockPageCombine(const Relation relation, const BlockNumber oldblkno, const BlockNumber newblkno); extern void TransferPredicateLocksToHeapRelation(const Relation relation); extern void ReleasePredicateLocks(const bool isCommit); /* conflict detection (may also trigger rollback) */ ! extern void CheckForSerializableConflictOut(const bool valid, const Relation relation, const HeapTuple tuple, const Buffer buffer); extern void CheckForSerializableConflictIn(const Relation relation, const HeapTuple tuple, const Buffer buffer); extern void CheckTableForSerializableConflictIn(const Relation relation); --- 44,60 ---- /* predicate lock maintenance */ extern Snapshot RegisterSerializableTransaction(Snapshot snapshot); extern void RegisterPredicateLockingXid(const TransactionId xid); ! extern void PredicateLockRelation(const Relation relation, const Snapshot snapshot); ! extern void PredicateLockPage(const Relation relation, const BlockNumber blkno, const Snapshot snapshot); ! extern void PredicateLockTuple(const Relation relation, const HeapTuple tuple, const Snapshot snapshot); extern void PredicateLockPageSplit(const Relation relation, const BlockNumber oldblkno, const BlockNumber newblkno); extern void PredicateLockPageCombine(const Relation relation, const BlockNumber oldblkno, const BlockNumber newblkno); extern void TransferPredicateLocksToHeapRelation(const Relation relation); extern void ReleasePredicateLocks(const bool isCommit); /* conflict detection (may also trigger rollback) */ ! extern void CheckForSerializableConflictOut(const bool valid, const Relation relation, const HeapTuple tuple, ! const Buffer buffer, const Snapshot snapshot); extern void CheckForSerializableConflictIn(const Relation relation, const HeapTuple tuple, const Buffer buffer); extern void CheckTableForSerializableConflictIn(const Relation relation);