*** a/src/backend/access/nbtree/nbtsearch.c --- b/src/backend/access/nbtree/nbtsearch.c *************** *** 849,856 **** _bt_first(IndexScanDesc scan, ScanDirection dir) if (!BufferIsValid(buf)) { /* ! * We only get here if the index is completely empty. ! * Lock relation because nothing finer to lock exists. */ PredicateLockRelation(rel, scan->xs_snapshot); return false; --- 849,856 ---- if (!BufferIsValid(buf)) { /* ! * We only get here if the index is completely empty. Lock relation ! * because nothing finer to lock exists. */ PredicateLockRelation(rel, scan->xs_snapshot); return false; *** a/src/backend/access/transam/twophase_rmgr.c --- b/src/backend/access/transam/twophase_rmgr.c *************** *** 26,32 **** const TwoPhaseCallback twophase_recover_callbacks[TWOPHASE_RM_MAX_ID + 1] = NULL, /* END ID */ lock_twophase_recover, /* Lock */ NULL, /* pgstat */ ! multixact_twophase_recover, /* MultiXact */ predicatelock_twophase_recover /* PredicateLock */ }; --- 26,32 ---- NULL, /* END ID */ lock_twophase_recover, /* Lock */ NULL, /* pgstat */ ! multixact_twophase_recover, /* MultiXact */ predicatelock_twophase_recover /* PredicateLock */ }; *************** *** 44,50 **** const TwoPhaseCallback twophase_postabort_callbacks[TWOPHASE_RM_MAX_ID + 1] = NULL, /* END ID */ lock_twophase_postabort, /* Lock */ pgstat_twophase_postabort, /* pgstat */ ! multixact_twophase_postabort, /* MultiXact */ NULL /* PredicateLock */ }; --- 44,50 ---- NULL, /* END ID */ lock_twophase_postabort, /* Lock */ pgstat_twophase_postabort, /* pgstat */ ! multixact_twophase_postabort, /* MultiXact */ NULL /* PredicateLock */ }; *** a/src/backend/storage/lmgr/predicate.c --- b/src/backend/storage/lmgr/predicate.c *************** *** 483,492 **** SerializationNeededForRead(Relation relation, Snapshot snapshot) * MySerializableXact, so that subsequent calls to this function can exit * quickly. * ! * A transaction is flagged as RO_SAFE if all concurrent R/W ! * transactions commit without having conflicts out to an earlier ! * snapshot, thus ensuring that no conflicts are possible for this ! * transaction. */ if (SxactIsROSafe(MySerializableXact)) { --- 483,491 ---- * MySerializableXact, so that subsequent calls to this function can exit * quickly. * ! * A transaction is flagged as RO_SAFE if all concurrent R/W transactions ! * commit without having conflicts out to an earlier snapshot, thus ! * ensuring that no conflicts are possible for this transaction. */ if (SxactIsROSafe(MySerializableXact)) { *************** *** 498,504 **** SerializationNeededForRead(Relation relation, Snapshot snapshot) if (!PredicateLockingNeededForRelation(relation)) return false; ! return true; /* no excuse to skip predicate locking */ } /* --- 497,503 ---- if (!PredicateLockingNeededForRelation(relation)) return false; ! return true; /* no excuse to skip predicate locking */ } /* *************** *** 516,522 **** SerializationNeededForWrite(Relation relation) if (!PredicateLockingNeededForRelation(relation)) return false; ! return true; /* no excuse to skip predicate locking */ } --- 515,521 ---- if (!PredicateLockingNeededForRelation(relation)) return false; ! return true; /* no excuse to skip predicate locking */ } *** a/src/include/storage/predicate.h --- b/src/include/storage/predicate.h *************** *** 54,60 **** 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); --- 54,60 ---- /* 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); *** a/src/include/storage/predicate_internals.h --- b/src/include/storage/predicate_internals.h *************** *** 90,98 **** typedef struct SERIALIZABLEXACT int pid; /* pid of associated process */ } SERIALIZABLEXACT; ! #define SXACT_FLAG_COMMITTED 0x00000001 /* already committed */ ! #define SXACT_FLAG_PREPARED 0x00000002 /* about to commit */ ! #define SXACT_FLAG_DOOMED 0x00000004 /* will roll back */ /* * The following flag actually means that the flagged transaction has a * conflict out *to a transaction which committed ahead of it*. It's hard --- 90,98 ---- int pid; /* pid of associated process */ } SERIALIZABLEXACT; ! #define SXACT_FLAG_COMMITTED 0x00000001 /* already committed */ ! #define SXACT_FLAG_PREPARED 0x00000002 /* about to commit */ ! #define SXACT_FLAG_DOOMED 0x00000004 /* will roll back */ /* * The following flag actually means that the flagged transaction has a * conflict out *to a transaction which committed ahead of it*. It's hard *************** *** 132,139 **** typedef struct PredXactListData /* * These global variables are maintained when registering and cleaning up * serializable transactions. They must be global across all backends, ! * but are not needed outside the predicate.c source file. Protected ! * by SerializableXactHashLock. */ TransactionId SxactGlobalXmin; /* global xmin for active serializable * transactions */ --- 132,139 ---- /* * These global variables are maintained when registering and cleaning up * serializable transactions. They must be global across all backends, ! * but are not needed outside the predicate.c source file. Protected by ! * SerializableXactHashLock. */ TransactionId SxactGlobalXmin; /* global xmin for active serializable * transactions */