LCOV - code coverage report
Current view: top level - src/backend/storage/lmgr - predicate.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 978 1309 74.7 %
Date: 2023-12-05 08:11:01 Functions: 63 70 90.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * predicate.c
       4             :  *    POSTGRES predicate locking
       5             :  *    to support full serializable transaction isolation
       6             :  *
       7             :  *
       8             :  * The approach taken is to implement Serializable Snapshot Isolation (SSI)
       9             :  * as initially described in this paper:
      10             :  *
      11             :  *  Michael J. Cahill, Uwe Röhm, and Alan D. Fekete. 2008.
      12             :  *  Serializable isolation for snapshot databases.
      13             :  *  In SIGMOD '08: Proceedings of the 2008 ACM SIGMOD
      14             :  *  international conference on Management of data,
      15             :  *  pages 729-738, New York, NY, USA. ACM.
      16             :  *  http://doi.acm.org/10.1145/1376616.1376690
      17             :  *
      18             :  * and further elaborated in Cahill's doctoral thesis:
      19             :  *
      20             :  *  Michael James Cahill. 2009.
      21             :  *  Serializable Isolation for Snapshot Databases.
      22             :  *  Sydney Digital Theses.
      23             :  *  University of Sydney, School of Information Technologies.
      24             :  *  http://hdl.handle.net/2123/5353
      25             :  *
      26             :  *
      27             :  * Predicate locks for Serializable Snapshot Isolation (SSI) are SIREAD
      28             :  * locks, which are so different from normal locks that a distinct set of
      29             :  * structures is required to handle them.  They are needed to detect
      30             :  * rw-conflicts when the read happens before the write.  (When the write
      31             :  * occurs first, the reading transaction can check for a conflict by
      32             :  * examining the MVCC data.)
      33             :  *
      34             :  * (1)  Besides tuples actually read, they must cover ranges of tuples
      35             :  *      which would have been read based on the predicate.  This will
      36             :  *      require modelling the predicates through locks against database
      37             :  *      objects such as pages, index ranges, or entire tables.
      38             :  *
      39             :  * (2)  They must be kept in RAM for quick access.  Because of this, it
      40             :  *      isn't possible to always maintain tuple-level granularity -- when
      41             :  *      the space allocated to store these approaches exhaustion, a
      42             :  *      request for a lock may need to scan for situations where a single
      43             :  *      transaction holds many fine-grained locks which can be coalesced
      44             :  *      into a single coarser-grained lock.
      45             :  *
      46             :  * (3)  They never block anything; they are more like flags than locks
      47             :  *      in that regard; although they refer to database objects and are
      48             :  *      used to identify rw-conflicts with normal write locks.
      49             :  *
      50             :  * (4)  While they are associated with a transaction, they must survive
      51             :  *      a successful COMMIT of that transaction, and remain until all
      52             :  *      overlapping transactions complete.  This even means that they
      53             :  *      must survive termination of the transaction's process.  If a
      54             :  *      top level transaction is rolled back, however, it is immediately
      55             :  *      flagged so that it can be ignored, and its SIREAD locks can be
      56             :  *      released any time after that.
      57             :  *
      58             :  * (5)  The only transactions which create SIREAD locks or check for
      59             :  *      conflicts with them are serializable transactions.
      60             :  *
      61             :  * (6)  When a write lock for a top level transaction is found to cover
      62             :  *      an existing SIREAD lock for the same transaction, the SIREAD lock
      63             :  *      can be deleted.
      64             :  *
      65             :  * (7)  A write from a serializable transaction must ensure that an xact
      66             :  *      record exists for the transaction, with the same lifespan (until
      67             :  *      all concurrent transaction complete or the transaction is rolled
      68             :  *      back) so that rw-dependencies to that transaction can be
      69             :  *      detected.
      70             :  *
      71             :  * We use an optimization for read-only transactions. Under certain
      72             :  * circumstances, a read-only transaction's snapshot can be shown to
      73             :  * never have conflicts with other transactions.  This is referred to
      74             :  * as a "safe" snapshot (and one known not to be is "unsafe").
      75             :  * However, it can't be determined whether a snapshot is safe until
      76             :  * all concurrent read/write transactions complete.
      77             :  *
      78             :  * Once a read-only transaction is known to have a safe snapshot, it
      79             :  * can release its predicate locks and exempt itself from further
      80             :  * predicate lock tracking. READ ONLY DEFERRABLE transactions run only
      81             :  * on safe snapshots, waiting as necessary for one to be available.
      82             :  *
      83             :  *
      84             :  * Lightweight locks to manage access to the predicate locking shared
      85             :  * memory objects must be taken in this order, and should be released in
      86             :  * reverse order:
      87             :  *
      88             :  *  SerializableFinishedListLock
      89             :  *      - Protects the list of transactions which have completed but which
      90             :  *          may yet matter because they overlap still-active transactions.
      91             :  *
      92             :  *  SerializablePredicateListLock
      93             :  *      - Protects the linked list of locks held by a transaction.  Note
      94             :  *          that the locks themselves are also covered by the partition
      95             :  *          locks of their respective lock targets; this lock only affects
      96             :  *          the linked list connecting the locks related to a transaction.
      97             :  *      - All transactions share this single lock (with no partitioning).
      98             :  *      - There is never a need for a process other than the one running
      99             :  *          an active transaction to walk the list of locks held by that
     100             :  *          transaction, except parallel query workers sharing the leader's
     101             :  *          transaction.  In the parallel case, an extra per-sxact lock is
     102             :  *          taken; see below.
     103             :  *      - It is relatively infrequent that another process needs to
     104             :  *          modify the list for a transaction, but it does happen for such
     105             :  *          things as index page splits for pages with predicate locks and
     106             :  *          freeing of predicate locked pages by a vacuum process.  When
     107             :  *          removing a lock in such cases, the lock itself contains the
     108             :  *          pointers needed to remove it from the list.  When adding a
     109             :  *          lock in such cases, the lock can be added using the anchor in
     110             :  *          the transaction structure.  Neither requires walking the list.
     111             :  *      - Cleaning up the list for a terminated transaction is sometimes
     112             :  *          not done on a retail basis, in which case no lock is required.
     113             :  *      - Due to the above, a process accessing its active transaction's
     114             :  *          list always uses a shared lock, regardless of whether it is
     115             :  *          walking or maintaining the list.  This improves concurrency
     116             :  *          for the common access patterns.
     117             :  *      - A process which needs to alter the list of a transaction other
     118             :  *          than its own active transaction must acquire an exclusive
     119             :  *          lock.
     120             :  *
     121             :  *  SERIALIZABLEXACT's member 'perXactPredicateListLock'
     122             :  *      - Protects the linked list of predicate locks held by a transaction.
     123             :  *          Only needed for parallel mode, where multiple backends share the
     124             :  *          same SERIALIZABLEXACT object.  Not needed if
     125             :  *          SerializablePredicateListLock is held exclusively.
     126             :  *
     127             :  *  PredicateLockHashPartitionLock(hashcode)
     128             :  *      - The same lock protects a target, all locks on that target, and
     129             :  *          the linked list of locks on the target.
     130             :  *      - When more than one is needed, acquire in ascending address order.
     131             :  *      - When all are needed (rare), acquire in ascending index order with
     132             :  *          PredicateLockHashPartitionLockByIndex(index).
     133             :  *
     134             :  *  SerializableXactHashLock
     135             :  *      - Protects both PredXact and SerializableXidHash.
     136             :  *
     137             :  *
     138             :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
     139             :  * Portions Copyright (c) 1994, Regents of the University of California
     140             :  *
     141             :  *
     142             :  * IDENTIFICATION
     143             :  *    src/backend/storage/lmgr/predicate.c
     144             :  *
     145             :  *-------------------------------------------------------------------------
     146             :  */
     147             : /*
     148             :  * INTERFACE ROUTINES
     149             :  *
     150             :  * housekeeping for setting up shared memory predicate lock structures
     151             :  *      InitPredicateLocks(void)
     152             :  *      PredicateLockShmemSize(void)
     153             :  *
     154             :  * predicate lock reporting
     155             :  *      GetPredicateLockStatusData(void)
     156             :  *      PageIsPredicateLocked(Relation relation, BlockNumber blkno)
     157             :  *
     158             :  * predicate lock maintenance
     159             :  *      GetSerializableTransactionSnapshot(Snapshot snapshot)
     160             :  *      SetSerializableTransactionSnapshot(Snapshot snapshot,
     161             :  *                                         VirtualTransactionId *sourcevxid)
     162             :  *      RegisterPredicateLockingXid(void)
     163             :  *      PredicateLockRelation(Relation relation, Snapshot snapshot)
     164             :  *      PredicateLockPage(Relation relation, BlockNumber blkno,
     165             :  *                      Snapshot snapshot)
     166             :  *      PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot,
     167             :  *                       TransactionId tuple_xid)
     168             :  *      PredicateLockPageSplit(Relation relation, BlockNumber oldblkno,
     169             :  *                             BlockNumber newblkno)
     170             :  *      PredicateLockPageCombine(Relation relation, BlockNumber oldblkno,
     171             :  *                               BlockNumber newblkno)
     172             :  *      TransferPredicateLocksToHeapRelation(Relation relation)
     173             :  *      ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
     174             :  *
     175             :  * conflict detection (may also trigger rollback)
     176             :  *      CheckForSerializableConflictOut(Relation relation, TransactionId xid,
     177             :  *                                      Snapshot snapshot)
     178             :  *      CheckForSerializableConflictIn(Relation relation, ItemPointer tid,
     179             :  *                                     BlockNumber blkno)
     180             :  *      CheckTableForSerializableConflictIn(Relation relation)
     181             :  *
     182             :  * final rollback checking
     183             :  *      PreCommit_CheckForSerializationFailure(void)
     184             :  *
     185             :  * two-phase commit support
     186             :  *      AtPrepare_PredicateLocks(void);
     187             :  *      PostPrepare_PredicateLocks(TransactionId xid);
     188             :  *      PredicateLockTwoPhaseFinish(TransactionId xid, bool isCommit);
     189             :  *      predicatelock_twophase_recover(TransactionId xid, uint16 info,
     190             :  *                                     void *recdata, uint32 len);
     191             :  */
     192             : 
     193             : #include "postgres.h"
     194             : 
     195             : #include "access/parallel.h"
     196             : #include "access/slru.h"
     197             : #include "access/subtrans.h"
     198             : #include "access/transam.h"
     199             : #include "access/twophase.h"
     200             : #include "access/twophase_rmgr.h"
     201             : #include "access/xact.h"
     202             : #include "access/xlog.h"
     203             : #include "miscadmin.h"
     204             : #include "pgstat.h"
     205             : #include "port/pg_lfind.h"
     206             : #include "storage/bufmgr.h"
     207             : #include "storage/predicate.h"
     208             : #include "storage/predicate_internals.h"
     209             : #include "storage/proc.h"
     210             : #include "storage/procarray.h"
     211             : #include "utils/rel.h"
     212             : #include "utils/snapmgr.h"
     213             : 
     214             : /* Uncomment the next line to test the graceful degradation code. */
     215             : /* #define TEST_SUMMARIZE_SERIAL */
     216             : 
     217             : /*
     218             :  * Test the most selective fields first, for performance.
     219             :  *
     220             :  * a is covered by b if all of the following hold:
     221             :  *  1) a.database = b.database
     222             :  *  2) a.relation = b.relation
     223             :  *  3) b.offset is invalid (b is page-granularity or higher)
     224             :  *  4) either of the following:
     225             :  *      4a) a.offset is valid (a is tuple-granularity) and a.page = b.page
     226             :  *   or 4b) a.offset is invalid and b.page is invalid (a is
     227             :  *          page-granularity and b is relation-granularity
     228             :  */
     229             : #define TargetTagIsCoveredBy(covered_target, covering_target)           \
     230             :     ((GET_PREDICATELOCKTARGETTAG_RELATION(covered_target) == /* (2) */  \
     231             :       GET_PREDICATELOCKTARGETTAG_RELATION(covering_target))             \
     232             :      && (GET_PREDICATELOCKTARGETTAG_OFFSET(covering_target) ==          \
     233             :          InvalidOffsetNumber)                                /* (3) */  \
     234             :      && (((GET_PREDICATELOCKTARGETTAG_OFFSET(covered_target) !=         \
     235             :            InvalidOffsetNumber)                              /* (4a) */ \
     236             :           && (GET_PREDICATELOCKTARGETTAG_PAGE(covering_target) ==       \
     237             :               GET_PREDICATELOCKTARGETTAG_PAGE(covered_target)))         \
     238             :          || ((GET_PREDICATELOCKTARGETTAG_PAGE(covering_target) ==       \
     239             :               InvalidBlockNumber)                            /* (4b) */ \
     240             :              && (GET_PREDICATELOCKTARGETTAG_PAGE(covered_target)        \
     241             :                  != InvalidBlockNumber)))                               \
     242             :      && (GET_PREDICATELOCKTARGETTAG_DB(covered_target) ==    /* (1) */  \
     243             :          GET_PREDICATELOCKTARGETTAG_DB(covering_target)))
     244             : 
     245             : /*
     246             :  * The predicate locking target and lock shared hash tables are partitioned to
     247             :  * reduce contention.  To determine which partition a given target belongs to,
     248             :  * compute the tag's hash code with PredicateLockTargetTagHashCode(), then
     249             :  * apply one of these macros.
     250             :  * NB: NUM_PREDICATELOCK_PARTITIONS must be a power of 2!
     251             :  */
     252             : #define PredicateLockHashPartition(hashcode) \
     253             :     ((hashcode) % NUM_PREDICATELOCK_PARTITIONS)
     254             : #define PredicateLockHashPartitionLock(hashcode) \
     255             :     (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + \
     256             :         PredicateLockHashPartition(hashcode)].lock)
     257             : #define PredicateLockHashPartitionLockByIndex(i) \
     258             :     (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
     259             : 
     260             : #define NPREDICATELOCKTARGETENTS() \
     261             :     mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
     262             : 
     263             : #define SxactIsOnFinishedList(sxact) (!dlist_node_is_detached(&(sxact)->finishedLink))
     264             : 
     265             : /*
     266             :  * Note that a sxact is marked "prepared" once it has passed
     267             :  * PreCommit_CheckForSerializationFailure, even if it isn't using
     268             :  * 2PC. This is the point at which it can no longer be aborted.
     269             :  *
     270             :  * The PREPARED flag remains set after commit, so SxactIsCommitted
     271             :  * implies SxactIsPrepared.
     272             :  */
     273             : #define SxactIsCommitted(sxact) (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)
     274             : #define SxactIsPrepared(sxact) (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)
     275             : #define SxactIsRolledBack(sxact) (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0)
     276             : #define SxactIsDoomed(sxact) (((sxact)->flags & SXACT_FLAG_DOOMED) != 0)
     277             : #define SxactIsReadOnly(sxact) (((sxact)->flags & SXACT_FLAG_READ_ONLY) != 0)
     278             : #define SxactHasSummaryConflictIn(sxact) (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_IN) != 0)
     279             : #define SxactHasSummaryConflictOut(sxact) (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_OUT) != 0)
     280             : /*
     281             :  * The following macro actually means that the specified transaction has a
     282             :  * conflict out *to a transaction which committed ahead of it*.  It's hard
     283             :  * to get that into a name of a reasonable length.
     284             :  */
     285             : #define SxactHasConflictOut(sxact) (((sxact)->flags & SXACT_FLAG_CONFLICT_OUT) != 0)
     286             : #define SxactIsDeferrableWaiting(sxact) (((sxact)->flags & SXACT_FLAG_DEFERRABLE_WAITING) != 0)
     287             : #define SxactIsROSafe(sxact) (((sxact)->flags & SXACT_FLAG_RO_SAFE) != 0)
     288             : #define SxactIsROUnsafe(sxact) (((sxact)->flags & SXACT_FLAG_RO_UNSAFE) != 0)
     289             : #define SxactIsPartiallyReleased(sxact) (((sxact)->flags & SXACT_FLAG_PARTIALLY_RELEASED) != 0)
     290             : 
     291             : /*
     292             :  * Compute the hash code associated with a PREDICATELOCKTARGETTAG.
     293             :  *
     294             :  * To avoid unnecessary recomputations of the hash code, we try to do this
     295             :  * just once per function, and then pass it around as needed.  Aside from
     296             :  * passing the hashcode to hash_search_with_hash_value(), we can extract
     297             :  * the lock partition number from the hashcode.
     298             :  */
     299             : #define PredicateLockTargetTagHashCode(predicatelocktargettag) \
     300             :     get_hash_value(PredicateLockTargetHash, predicatelocktargettag)
     301             : 
     302             : /*
     303             :  * Given a predicate lock tag, and the hash for its target,
     304             :  * compute the lock hash.
     305             :  *
     306             :  * To make the hash code also depend on the transaction, we xor the sxid
     307             :  * struct's address into the hash code, left-shifted so that the
     308             :  * partition-number bits don't change.  Since this is only a hash, we
     309             :  * don't care if we lose high-order bits of the address; use an
     310             :  * intermediate variable to suppress cast-pointer-to-int warnings.
     311             :  */
     312             : #define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash) \
     313             :     ((targethash) ^ ((uint32) PointerGetDatum((predicatelocktag)->myXact)) \
     314             :      << LOG2_NUM_PREDICATELOCK_PARTITIONS)
     315             : 
     316             : 
     317             : /*
     318             :  * The SLRU buffer area through which we access the old xids.
     319             :  */
     320             : static SlruCtlData SerialSlruCtlData;
     321             : 
     322             : #define SerialSlruCtl           (&SerialSlruCtlData)
     323             : 
     324             : #define SERIAL_PAGESIZE         BLCKSZ
     325             : #define SERIAL_ENTRYSIZE            sizeof(SerCommitSeqNo)
     326             : #define SERIAL_ENTRIESPERPAGE   (SERIAL_PAGESIZE / SERIAL_ENTRYSIZE)
     327             : 
     328             : /*
     329             :  * Set maximum pages based on the number needed to track all transactions.
     330             :  */
     331             : #define SERIAL_MAX_PAGE         (MaxTransactionId / SERIAL_ENTRIESPERPAGE)
     332             : 
     333             : #define SerialNextPage(page) (((page) >= SERIAL_MAX_PAGE) ? 0 : (page) + 1)
     334             : 
     335             : #define SerialValue(slotno, xid) (*((SerCommitSeqNo *) \
     336             :     (SerialSlruCtl->shared->page_buffer[slotno] + \
     337             :     ((((uint32) (xid)) % SERIAL_ENTRIESPERPAGE) * SERIAL_ENTRYSIZE))))
     338             : 
     339             : #define SerialPage(xid) (((uint32) (xid)) / SERIAL_ENTRIESPERPAGE)
     340             : 
     341             : typedef struct SerialControlData
     342             : {
     343             :     int         headPage;       /* newest initialized page */
     344             :     TransactionId headXid;      /* newest valid Xid in the SLRU */
     345             :     TransactionId tailXid;      /* oldest xmin we might be interested in */
     346             : }           SerialControlData;
     347             : 
     348             : typedef struct SerialControlData *SerialControl;
     349             : 
     350             : static SerialControl serialControl;
     351             : 
     352             : /*
     353             :  * When the oldest committed transaction on the "finished" list is moved to
     354             :  * SLRU, its predicate locks will be moved to this "dummy" transaction,
     355             :  * collapsing duplicate targets.  When a duplicate is found, the later
     356             :  * commitSeqNo is used.
     357             :  */
     358             : static SERIALIZABLEXACT *OldCommittedSxact;
     359             : 
     360             : 
     361             : /*
     362             :  * These configuration variables are used to set the predicate lock table size
     363             :  * and to control promotion of predicate locks to coarser granularity in an
     364             :  * attempt to degrade performance (mostly as false positive serialization
     365             :  * failure) gracefully in the face of memory pressure.
     366             :  */
     367             : int         max_predicate_locks_per_xact;   /* in guc_tables.c */
     368             : int         max_predicate_locks_per_relation;   /* in guc_tables.c */
     369             : int         max_predicate_locks_per_page;   /* in guc_tables.c */
     370             : 
     371             : /*
     372             :  * This provides a list of objects in order to track transactions
     373             :  * participating in predicate locking.  Entries in the list are fixed size,
     374             :  * and reside in shared memory.  The memory address of an entry must remain
     375             :  * fixed during its lifetime.  The list will be protected from concurrent
     376             :  * update externally; no provision is made in this code to manage that.  The
     377             :  * number of entries in the list, and the size allowed for each entry is
     378             :  * fixed upon creation.
     379             :  */
     380             : static PredXactList PredXact;
     381             : 
     382             : /*
     383             :  * This provides a pool of RWConflict data elements to use in conflict lists
     384             :  * between transactions.
     385             :  */
     386             : static RWConflictPoolHeader RWConflictPool;
     387             : 
     388             : /*
     389             :  * The predicate locking hash tables are in shared memory.
     390             :  * Each backend keeps pointers to them.
     391             :  */
     392             : static HTAB *SerializableXidHash;
     393             : static HTAB *PredicateLockTargetHash;
     394             : static HTAB *PredicateLockHash;
     395             : static dlist_head *FinishedSerializableTransactions;
     396             : 
     397             : /*
     398             :  * Tag for a dummy entry in PredicateLockTargetHash. By temporarily removing
     399             :  * this entry, you can ensure that there's enough scratch space available for
     400             :  * inserting one entry in the hash table. This is an otherwise-invalid tag.
     401             :  */
     402             : static const PREDICATELOCKTARGETTAG ScratchTargetTag = {0, 0, 0, 0};
     403             : static uint32 ScratchTargetTagHash;
     404             : static LWLock *ScratchPartitionLock;
     405             : 
     406             : /*
     407             :  * The local hash table used to determine when to combine multiple fine-
     408             :  * grained locks into a single courser-grained lock.
     409             :  */
     410             : static HTAB *LocalPredicateLockHash = NULL;
     411             : 
     412             : /*
     413             :  * Keep a pointer to the currently-running serializable transaction (if any)
     414             :  * for quick reference. Also, remember if we have written anything that could
     415             :  * cause a rw-conflict.
     416             :  */
     417             : static SERIALIZABLEXACT *MySerializableXact = InvalidSerializableXact;
     418             : static bool MyXactDidWrite = false;
     419             : 
     420             : /*
     421             :  * The SXACT_FLAG_RO_UNSAFE optimization might lead us to release
     422             :  * MySerializableXact early.  If that happens in a parallel query, the leader
     423             :  * needs to defer the destruction of the SERIALIZABLEXACT until end of
     424             :  * transaction, because the workers still have a reference to it.  In that
     425             :  * case, the leader stores it here.
     426             :  */
     427             : static SERIALIZABLEXACT *SavedSerializableXact = InvalidSerializableXact;
     428             : 
     429             : /* local functions */
     430             : 
     431             : static SERIALIZABLEXACT *CreatePredXact(void);
     432             : static void ReleasePredXact(SERIALIZABLEXACT *sxact);
     433             : 
     434             : static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer);
     435             : static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer);
     436             : static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact);
     437             : static void ReleaseRWConflict(RWConflict conflict);
     438             : static void FlagSxactUnsafe(SERIALIZABLEXACT *sxact);
     439             : 
     440             : static bool SerialPagePrecedesLogically(int64 page1, int64 page2);
     441             : static void SerialInit(void);
     442             : static void SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo);
     443             : static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid);
     444             : static void SerialSetActiveSerXmin(TransactionId xid);
     445             : 
     446             : static uint32 predicatelock_hash(const void *key, Size keysize);
     447             : static void SummarizeOldestCommittedSxact(void);
     448             : static Snapshot GetSafeSnapshot(Snapshot origSnapshot);
     449             : static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot,
     450             :                                                       VirtualTransactionId *sourcevxid,
     451             :                                                       int sourcepid);
     452             : static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag);
     453             : static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag,
     454             :                                       PREDICATELOCKTARGETTAG *parent);
     455             : static bool CoarserLockCovers(const PREDICATELOCKTARGETTAG *newtargettag);
     456             : static void RemoveScratchTarget(bool lockheld);
     457             : static void RestoreScratchTarget(bool lockheld);
     458             : static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target,
     459             :                                        uint32 targettaghash);
     460             : static void DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag);
     461             : static int  MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag);
     462             : static bool CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag);
     463             : static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag);
     464             : static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag,
     465             :                                 uint32 targettaghash,
     466             :                                 SERIALIZABLEXACT *sxact);
     467             : static void DeleteLockTarget(PREDICATELOCKTARGET *target, uint32 targettaghash);
     468             : static bool TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag,
     469             :                                               PREDICATELOCKTARGETTAG newtargettag,
     470             :                                               bool removeOld);
     471             : static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag);
     472             : static void DropAllPredicateLocksFromTable(Relation relation,
     473             :                                            bool transfer);
     474             : static void SetNewSxactGlobalXmin(void);
     475             : static void ClearOldPredicateLocks(void);
     476             : static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
     477             :                                        bool summarize);
     478             : static bool XidIsConcurrent(TransactionId xid);
     479             : static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag);
     480             : static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer);
     481             : static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
     482             :                                                     SERIALIZABLEXACT *writer);
     483             : static void CreateLocalPredicateLockHash(void);
     484             : static void ReleasePredicateLocksLocal(void);
     485             : 
     486             : 
     487             : /*------------------------------------------------------------------------*/
     488             : 
     489             : /*
     490             :  * Does this relation participate in predicate locking? Temporary and system
     491             :  * relations are exempt.
     492             :  */
     493             : static inline bool
     494      287918 : PredicateLockingNeededForRelation(Relation relation)
     495             : {
     496      401226 :     return !(relation->rd_id < FirstUnpinnedObjectId ||
     497      113308 :              RelationUsesLocalBuffers(relation));
     498             : }
     499             : 
     500             : /*
     501             :  * When a public interface method is called for a read, this is the test to
     502             :  * see if we should do a quick return.
     503             :  *
     504             :  * Note: this function has side-effects! If this transaction has been flagged
     505             :  * as RO-safe since the last call, we release all predicate locks and reset
     506             :  * MySerializableXact. That makes subsequent calls to return quickly.
     507             :  *
     508             :  * This is marked as 'inline' to eliminate the function call overhead in the
     509             :  * common case that serialization is not needed.
     510             :  */
     511             : static inline bool
     512   232747914 : SerializationNeededForRead(Relation relation, Snapshot snapshot)
     513             : {
     514             :     /* Nothing to do if this is not a serializable transaction */
     515   232747914 :     if (MySerializableXact == InvalidSerializableXact)
     516   232471646 :         return false;
     517             : 
     518             :     /*
     519             :      * Don't acquire locks or conflict when scanning with a special snapshot.
     520             :      * This excludes things like CLUSTER and REINDEX. They use the wholesale
     521             :      * functions TransferPredicateLocksToHeapRelation() and
     522             :      * CheckTableForSerializableConflictIn() to participate in serialization,
     523             :      * but the scans involved don't need serialization.
     524             :      */
     525      276268 :     if (!IsMVCCSnapshot(snapshot))
     526        2900 :         return false;
     527             : 
     528             :     /*
     529             :      * Check if we have just become "RO-safe". If we have, immediately release
     530             :      * all locks as they're not needed anymore. This also resets
     531             :      * MySerializableXact, so that subsequent calls to this function can exit
     532             :      * quickly.
     533             :      *
     534             :      * A transaction is flagged as RO_SAFE if all concurrent R/W transactions
     535             :      * commit without having conflicts out to an earlier snapshot, thus
     536             :      * ensuring that no conflicts are possible for this transaction.
     537             :      */
     538      273368 :     if (SxactIsROSafe(MySerializableXact))
     539             :     {
     540          66 :         ReleasePredicateLocks(false, true);
     541          66 :         return false;
     542             :     }
     543             : 
     544             :     /* Check if the relation doesn't participate in predicate locking */
     545      273302 :     if (!PredicateLockingNeededForRelation(relation))
     546      169696 :         return false;
     547             : 
     548      103606 :     return true;                /* no excuse to skip predicate locking */
     549             : }
     550             : 
     551             : /*
     552             :  * Like SerializationNeededForRead(), but called on writes.
     553             :  * The logic is the same, but there is no snapshot and we can't be RO-safe.
     554             :  */
     555             : static inline bool
     556    28665798 : SerializationNeededForWrite(Relation relation)
     557             : {
     558             :     /* Nothing to do if this is not a serializable transaction */
     559    28665798 :     if (MySerializableXact == InvalidSerializableXact)
     560    28651684 :         return false;
     561             : 
     562             :     /* Check if the relation doesn't participate in predicate locking */
     563       14114 :     if (!PredicateLockingNeededForRelation(relation))
     564        5258 :         return false;
     565             : 
     566        8856 :     return true;                /* no excuse to skip predicate locking */
     567             : }
     568             : 
     569             : 
     570             : /*------------------------------------------------------------------------*/
     571             : 
     572             : /*
     573             :  * These functions are a simple implementation of a list for this specific
     574             :  * type of struct.  If there is ever a generalized shared memory list, we
     575             :  * should probably switch to that.
     576             :  */
     577             : static SERIALIZABLEXACT *
     578        4844 : CreatePredXact(void)
     579             : {
     580             :     SERIALIZABLEXACT *sxact;
     581             : 
     582        4844 :     if (dlist_is_empty(&PredXact->availableList))
     583           0 :         return NULL;
     584             : 
     585        4844 :     sxact = dlist_container(SERIALIZABLEXACT, xactLink,
     586             :                             dlist_pop_head_node(&PredXact->availableList));
     587        4844 :     dlist_push_tail(&PredXact->activeList, &sxact->xactLink);
     588        4844 :     return sxact;
     589             : }
     590             : 
     591             : static void
     592        3282 : ReleasePredXact(SERIALIZABLEXACT *sxact)
     593             : {
     594             :     Assert(ShmemAddrIsValid(sxact));
     595             : 
     596        3282 :     dlist_delete(&sxact->xactLink);
     597        3282 :     dlist_push_tail(&PredXact->availableList, &sxact->xactLink);
     598        3282 : }
     599             : 
     600             : /*------------------------------------------------------------------------*/
     601             : 
     602             : /*
     603             :  * These functions manage primitive access to the RWConflict pool and lists.
     604             :  */
     605             : static bool
     606        3736 : RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
     607             : {
     608             :     dlist_iter  iter;
     609             : 
     610             :     Assert(reader != writer);
     611             : 
     612             :     /* Check the ends of the purported conflict first. */
     613        3736 :     if (SxactIsDoomed(reader)
     614        3736 :         || SxactIsDoomed(writer)
     615        3736 :         || dlist_is_empty(&reader->outConflicts)
     616        1134 :         || dlist_is_empty(&writer->inConflicts))
     617        2682 :         return false;
     618             : 
     619             :     /*
     620             :      * A conflict is possible; walk the list to find out.
     621             :      *
     622             :      * The unconstify is needed as we have no const version of
     623             :      * dlist_foreach().
     624             :      */
     625        1086 :     dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->outConflicts)
     626             :     {
     627        1054 :         RWConflict  conflict =
     628        1054 :             dlist_container(RWConflictData, outLink, iter.cur);
     629             : 
     630        1054 :         if (conflict->sxactIn == writer)
     631        1022 :             return true;
     632             :     }
     633             : 
     634             :     /* No conflict found. */
     635          32 :     return false;
     636             : }
     637             : 
     638             : static void
     639        1560 : SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
     640             : {
     641             :     RWConflict  conflict;
     642             : 
     643             :     Assert(reader != writer);
     644             :     Assert(!RWConflictExists(reader, writer));
     645             : 
     646        1560 :     if (dlist_is_empty(&RWConflictPool->availableList))
     647           0 :         ereport(ERROR,
     648             :                 (errcode(ERRCODE_OUT_OF_MEMORY),
     649             :                  errmsg("not enough elements in RWConflictPool to record a read/write conflict"),
     650             :                  errhint("You might need to run fewer transactions at a time or increase max_connections.")));
     651             : 
     652        1560 :     conflict = dlist_head_element(RWConflictData, outLink, &RWConflictPool->availableList);
     653        1560 :     dlist_delete(&conflict->outLink);
     654             : 
     655        1560 :     conflict->sxactOut = reader;
     656        1560 :     conflict->sxactIn = writer;
     657        1560 :     dlist_push_tail(&reader->outConflicts, &conflict->outLink);
     658        1560 :     dlist_push_tail(&writer->inConflicts, &conflict->inLink);
     659        1560 : }
     660             : 
     661             : static void
     662         264 : SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact,
     663             :                           SERIALIZABLEXACT *activeXact)
     664             : {
     665             :     RWConflict  conflict;
     666             : 
     667             :     Assert(roXact != activeXact);
     668             :     Assert(SxactIsReadOnly(roXact));
     669             :     Assert(!SxactIsReadOnly(activeXact));
     670             : 
     671         264 :     if (dlist_is_empty(&RWConflictPool->availableList))
     672           0 :         ereport(ERROR,
     673             :                 (errcode(ERRCODE_OUT_OF_MEMORY),
     674             :                  errmsg("not enough elements in RWConflictPool to record a potential read/write conflict"),
     675             :                  errhint("You might need to run fewer transactions at a time or increase max_connections.")));
     676             : 
     677         264 :     conflict = dlist_head_element(RWConflictData, outLink, &RWConflictPool->availableList);
     678         264 :     dlist_delete(&conflict->outLink);
     679             : 
     680         264 :     conflict->sxactOut = activeXact;
     681         264 :     conflict->sxactIn = roXact;
     682         264 :     dlist_push_tail(&activeXact->possibleUnsafeConflicts, &conflict->outLink);
     683         264 :     dlist_push_tail(&roXact->possibleUnsafeConflicts, &conflict->inLink);
     684         264 : }
     685             : 
     686             : static void
     687        1824 : ReleaseRWConflict(RWConflict conflict)
     688             : {
     689        1824 :     dlist_delete(&conflict->inLink);
     690        1824 :     dlist_delete(&conflict->outLink);
     691        1824 :     dlist_push_tail(&RWConflictPool->availableList, &conflict->outLink);
     692        1824 : }
     693             : 
     694             : static void
     695           6 : FlagSxactUnsafe(SERIALIZABLEXACT *sxact)
     696             : {
     697             :     dlist_mutable_iter iter;
     698             : 
     699             :     Assert(SxactIsReadOnly(sxact));
     700             :     Assert(!SxactIsROSafe(sxact));
     701             : 
     702           6 :     sxact->flags |= SXACT_FLAG_RO_UNSAFE;
     703             : 
     704             :     /*
     705             :      * We know this isn't a safe snapshot, so we can stop looking for other
     706             :      * potential conflicts.
     707             :      */
     708          12 :     dlist_foreach_modify(iter, &sxact->possibleUnsafeConflicts)
     709             :     {
     710           6 :         RWConflict  conflict =
     711           6 :             dlist_container(RWConflictData, inLink, iter.cur);
     712             : 
     713             :         Assert(!SxactIsReadOnly(conflict->sxactOut));
     714             :         Assert(sxact == conflict->sxactIn);
     715             : 
     716           6 :         ReleaseRWConflict(conflict);
     717             :     }
     718           6 : }
     719             : 
     720             : /*------------------------------------------------------------------------*/
     721             : 
     722             : /*
     723             :  * Decide whether a Serial page number is "older" for truncation purposes.
     724             :  * Analogous to CLOGPagePrecedes().
     725             :  */
     726             : static bool
     727           0 : SerialPagePrecedesLogically(int64 page1, int64 page2)
     728             : {
     729             :     TransactionId xid1;
     730             :     TransactionId xid2;
     731             : 
     732           0 :     xid1 = ((TransactionId) page1) * SERIAL_ENTRIESPERPAGE;
     733           0 :     xid1 += FirstNormalTransactionId + 1;
     734           0 :     xid2 = ((TransactionId) page2) * SERIAL_ENTRIESPERPAGE;
     735           0 :     xid2 += FirstNormalTransactionId + 1;
     736             : 
     737           0 :     return (TransactionIdPrecedes(xid1, xid2) &&
     738           0 :             TransactionIdPrecedes(xid1, xid2 + SERIAL_ENTRIESPERPAGE - 1));
     739             : }
     740             : 
     741             : #ifdef USE_ASSERT_CHECKING
     742             : static void
     743             : SerialPagePrecedesLogicallyUnitTests(void)
     744             : {
     745             :     int         per_page = SERIAL_ENTRIESPERPAGE,
     746             :                 offset = per_page / 2;
     747             :     int64       newestPage,
     748             :                 oldestPage,
     749             :                 headPage,
     750             :                 targetPage;
     751             :     TransactionId newestXact,
     752             :                 oldestXact;
     753             : 
     754             :     /* GetNewTransactionId() has assigned the last XID it can safely use. */
     755             :     newestPage = 2 * SLRU_PAGES_PER_SEGMENT - 1;    /* nothing special */
     756             :     newestXact = newestPage * per_page + offset;
     757             :     Assert(newestXact / per_page == newestPage);
     758             :     oldestXact = newestXact + 1;
     759             :     oldestXact -= 1U << 31;
     760             :     oldestPage = oldestXact / per_page;
     761             : 
     762             :     /*
     763             :      * In this scenario, the SLRU headPage pertains to the last ~1000 XIDs
     764             :      * assigned.  oldestXact finishes, ~2B XIDs having elapsed since it
     765             :      * started.  Further transactions cause us to summarize oldestXact to
     766             :      * tailPage.  Function must return false so SerialAdd() doesn't zero
     767             :      * tailPage (which may contain entries for other old, recently-finished
     768             :      * XIDs) and half the SLRU.  Reaching this requires burning ~2B XIDs in
     769             :      * single-user mode, a negligible possibility.
     770             :      */
     771             :     headPage = newestPage;
     772             :     targetPage = oldestPage;
     773             :     Assert(!SerialPagePrecedesLogically(headPage, targetPage));
     774             : 
     775             :     /*
     776             :      * In this scenario, the SLRU headPage pertains to oldestXact.  We're
     777             :      * summarizing an XID near newestXact.  (Assume few other XIDs used
     778             :      * SERIALIZABLE, hence the minimal headPage advancement.  Assume
     779             :      * oldestXact was long-running and only recently reached the SLRU.)
     780             :      * Function must return true to make SerialAdd() create targetPage.
     781             :      *
     782             :      * Today's implementation mishandles this case, but it doesn't matter
     783             :      * enough to fix.  Verify that the defect affects just one page by
     784             :      * asserting correct treatment of its prior page.  Reaching this case
     785             :      * requires burning ~2B XIDs in single-user mode, a negligible
     786             :      * possibility.  Moreover, if it does happen, the consequence would be
     787             :      * mild, namely a new transaction failing in SimpleLruReadPage().
     788             :      */
     789             :     headPage = oldestPage;
     790             :     targetPage = newestPage;
     791             :     Assert(SerialPagePrecedesLogically(headPage, targetPage - 1));
     792             : #if 0
     793             :     Assert(SerialPagePrecedesLogically(headPage, targetPage));
     794             : #endif
     795             : }
     796             : #endif
     797             : 
     798             : /*
     799             :  * Initialize for the tracking of old serializable committed xids.
     800             :  */
     801             : static void
     802        1562 : SerialInit(void)
     803             : {
     804             :     bool        found;
     805             : 
     806             :     /*
     807             :      * Set up SLRU management of the pg_serial data.
     808             :      */
     809        1562 :     SerialSlruCtl->PagePrecedes = SerialPagePrecedesLogically;
     810        1562 :     SimpleLruInit(SerialSlruCtl, "Serial",
     811        1562 :                   NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
     812             :                   LWTRANCHE_SERIAL_BUFFER, SYNC_HANDLER_NONE,
     813             :                   false);
     814             : #ifdef USE_ASSERT_CHECKING
     815             :     SerialPagePrecedesLogicallyUnitTests();
     816             : #endif
     817             :     SlruPagePrecedesUnitTests(SerialSlruCtl, SERIAL_ENTRIESPERPAGE);
     818             : 
     819             :     /*
     820             :      * Create or attach to the SerialControl structure.
     821             :      */
     822        1562 :     serialControl = (SerialControl)
     823        1562 :         ShmemInitStruct("SerialControlData", sizeof(SerialControlData), &found);
     824             : 
     825             :     Assert(found == IsUnderPostmaster);
     826        1562 :     if (!found)
     827             :     {
     828             :         /*
     829             :          * Set control information to reflect empty SLRU.
     830             :          */
     831        1562 :         serialControl->headPage = -1;
     832        1562 :         serialControl->headXid = InvalidTransactionId;
     833        1562 :         serialControl->tailXid = InvalidTransactionId;
     834             :     }
     835        1562 : }
     836             : 
     837             : /*
     838             :  * Record a committed read write serializable xid and the minimum
     839             :  * commitSeqNo of any transactions to which this xid had a rw-conflict out.
     840             :  * An invalid commitSeqNo means that there were no conflicts out from xid.
     841             :  */
     842             : static void
     843           0 : SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
     844             : {
     845             :     TransactionId tailXid;
     846             :     int64       targetPage;
     847             :     int         slotno;
     848             :     int64       firstZeroPage;
     849             :     bool        isNewPage;
     850             : 
     851             :     Assert(TransactionIdIsValid(xid));
     852             : 
     853           0 :     targetPage = SerialPage(xid);
     854             : 
     855           0 :     LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
     856             : 
     857             :     /*
     858             :      * If no serializable transactions are active, there shouldn't be anything
     859             :      * to push out to the SLRU.  Hitting this assert would mean there's
     860             :      * something wrong with the earlier cleanup logic.
     861             :      */
     862           0 :     tailXid = serialControl->tailXid;
     863             :     Assert(TransactionIdIsValid(tailXid));
     864             : 
     865             :     /*
     866             :      * If the SLRU is currently unused, zero out the whole active region from
     867             :      * tailXid to headXid before taking it into use. Otherwise zero out only
     868             :      * any new pages that enter the tailXid-headXid range as we advance
     869             :      * headXid.
     870             :      */
     871           0 :     if (serialControl->headPage < 0)
     872             :     {
     873           0 :         firstZeroPage = SerialPage(tailXid);
     874           0 :         isNewPage = true;
     875             :     }
     876             :     else
     877             :     {
     878           0 :         firstZeroPage = SerialNextPage(serialControl->headPage);
     879           0 :         isNewPage = SerialPagePrecedesLogically(serialControl->headPage,
     880             :                                                 targetPage);
     881             :     }
     882             : 
     883           0 :     if (!TransactionIdIsValid(serialControl->headXid)
     884           0 :         || TransactionIdFollows(xid, serialControl->headXid))
     885           0 :         serialControl->headXid = xid;
     886           0 :     if (isNewPage)
     887           0 :         serialControl->headPage = targetPage;
     888             : 
     889           0 :     if (isNewPage)
     890             :     {
     891             :         /* Initialize intervening pages. */
     892           0 :         while (firstZeroPage != targetPage)
     893             :         {
     894           0 :             (void) SimpleLruZeroPage(SerialSlruCtl, firstZeroPage);
     895           0 :             firstZeroPage = SerialNextPage(firstZeroPage);
     896             :         }
     897           0 :         slotno = SimpleLruZeroPage(SerialSlruCtl, targetPage);
     898             :     }
     899             :     else
     900           0 :         slotno = SimpleLruReadPage(SerialSlruCtl, targetPage, true, xid);
     901             : 
     902           0 :     SerialValue(slotno, xid) = minConflictCommitSeqNo;
     903           0 :     SerialSlruCtl->shared->page_dirty[slotno] = true;
     904             : 
     905           0 :     LWLockRelease(SerialSLRULock);
     906           0 : }
     907             : 
     908             : /*
     909             :  * Get the minimum commitSeqNo for any conflict out for the given xid.  For
     910             :  * a transaction which exists but has no conflict out, InvalidSerCommitSeqNo
     911             :  * will be returned.
     912             :  */
     913             : static SerCommitSeqNo
     914          48 : SerialGetMinConflictCommitSeqNo(TransactionId xid)
     915             : {
     916             :     TransactionId headXid;
     917             :     TransactionId tailXid;
     918             :     SerCommitSeqNo val;
     919             :     int         slotno;
     920             : 
     921             :     Assert(TransactionIdIsValid(xid));
     922             : 
     923          48 :     LWLockAcquire(SerialSLRULock, LW_SHARED);
     924          48 :     headXid = serialControl->headXid;
     925          48 :     tailXid = serialControl->tailXid;
     926          48 :     LWLockRelease(SerialSLRULock);
     927             : 
     928          48 :     if (!TransactionIdIsValid(headXid))
     929          48 :         return 0;
     930             : 
     931             :     Assert(TransactionIdIsValid(tailXid));
     932             : 
     933           0 :     if (TransactionIdPrecedes(xid, tailXid)
     934           0 :         || TransactionIdFollows(xid, headXid))
     935           0 :         return 0;
     936             : 
     937             :     /*
     938             :      * The following function must be called without holding SerialSLRULock,
     939             :      * but will return with that lock held, which must then be released.
     940             :      */
     941           0 :     slotno = SimpleLruReadPage_ReadOnly(SerialSlruCtl,
     942             :                                         SerialPage(xid), xid);
     943           0 :     val = SerialValue(slotno, xid);
     944           0 :     LWLockRelease(SerialSLRULock);
     945           0 :     return val;
     946             : }
     947             : 
     948             : /*
     949             :  * Call this whenever there is a new xmin for active serializable
     950             :  * transactions.  We don't need to keep information on transactions which
     951             :  * precede that.  InvalidTransactionId means none active, so everything in
     952             :  * the SLRU can be discarded.
     953             :  */
     954             : static void
     955        3398 : SerialSetActiveSerXmin(TransactionId xid)
     956             : {
     957        3398 :     LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
     958             : 
     959             :     /*
     960             :      * When no sxacts are active, nothing overlaps, set the xid values to
     961             :      * invalid to show that there are no valid entries.  Don't clear headPage,
     962             :      * though.  A new xmin might still land on that page, and we don't want to
     963             :      * repeatedly zero out the same page.
     964             :      */
     965        3398 :     if (!TransactionIdIsValid(xid))
     966             :     {
     967        1682 :         serialControl->tailXid = InvalidTransactionId;
     968        1682 :         serialControl->headXid = InvalidTransactionId;
     969        1682 :         LWLockRelease(SerialSLRULock);
     970        1682 :         return;
     971             :     }
     972             : 
     973             :     /*
     974             :      * When we're recovering prepared transactions, the global xmin might move
     975             :      * backwards depending on the order they're recovered. Normally that's not
     976             :      * OK, but during recovery no serializable transactions will commit, so
     977             :      * the SLRU is empty and we can get away with it.
     978             :      */
     979        1716 :     if (RecoveryInProgress())
     980             :     {
     981             :         Assert(serialControl->headPage < 0);
     982           0 :         if (!TransactionIdIsValid(serialControl->tailXid)
     983           0 :             || TransactionIdPrecedes(xid, serialControl->tailXid))
     984             :         {
     985           0 :             serialControl->tailXid = xid;
     986             :         }
     987           0 :         LWLockRelease(SerialSLRULock);
     988           0 :         return;
     989             :     }
     990             : 
     991             :     Assert(!TransactionIdIsValid(serialControl->tailXid)
     992             :            || TransactionIdFollows(xid, serialControl->tailXid));
     993             : 
     994        1716 :     serialControl->tailXid = xid;
     995             : 
     996        1716 :     LWLockRelease(SerialSLRULock);
     997             : }
     998             : 
     999             : /*
    1000             :  * Perform a checkpoint --- either during shutdown, or on-the-fly
    1001             :  *
    1002             :  * We don't have any data that needs to survive a restart, but this is a
    1003             :  * convenient place to truncate the SLRU.
    1004             :  */
    1005             : void
    1006        1512 : CheckPointPredicate(void)
    1007             : {
    1008             :     int         truncateCutoffPage;
    1009             : 
    1010        1512 :     LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
    1011             : 
    1012             :     /* Exit quickly if the SLRU is currently not in use. */
    1013        1512 :     if (serialControl->headPage < 0)
    1014             :     {
    1015        1512 :         LWLockRelease(SerialSLRULock);
    1016        1512 :         return;
    1017             :     }
    1018             : 
    1019           0 :     if (TransactionIdIsValid(serialControl->tailXid))
    1020             :     {
    1021             :         int         tailPage;
    1022             : 
    1023           0 :         tailPage = SerialPage(serialControl->tailXid);
    1024             : 
    1025             :         /*
    1026             :          * It is possible for the tailXid to be ahead of the headXid.  This
    1027             :          * occurs if we checkpoint while there are in-progress serializable
    1028             :          * transaction(s) advancing the tail but we are yet to summarize the
    1029             :          * transactions.  In this case, we cutoff up to the headPage and the
    1030             :          * next summary will advance the headXid.
    1031             :          */
    1032           0 :         if (SerialPagePrecedesLogically(tailPage, serialControl->headPage))
    1033             :         {
    1034             :             /* We can truncate the SLRU up to the page containing tailXid */
    1035           0 :             truncateCutoffPage = tailPage;
    1036             :         }
    1037             :         else
    1038           0 :             truncateCutoffPage = serialControl->headPage;
    1039             :     }
    1040             :     else
    1041             :     {
    1042             :         /*----------
    1043             :          * The SLRU is no longer needed. Truncate to head before we set head
    1044             :          * invalid.
    1045             :          *
    1046             :          * XXX: It's possible that the SLRU is not needed again until XID
    1047             :          * wrap-around has happened, so that the segment containing headPage
    1048             :          * that we leave behind will appear to be new again. In that case it
    1049             :          * won't be removed until XID horizon advances enough to make it
    1050             :          * current again.
    1051             :          *
    1052             :          * XXX: This should happen in vac_truncate_clog(), not in checkpoints.
    1053             :          * Consider this scenario, starting from a system with no in-progress
    1054             :          * transactions and VACUUM FREEZE having maximized oldestXact:
    1055             :          * - Start a SERIALIZABLE transaction.
    1056             :          * - Start, finish, and summarize a SERIALIZABLE transaction, creating
    1057             :          *   one SLRU page.
    1058             :          * - Consume XIDs to reach xidStopLimit.
    1059             :          * - Finish all transactions.  Due to the long-running SERIALIZABLE
    1060             :          *   transaction, earlier checkpoints did not touch headPage.  The
    1061             :          *   next checkpoint will change it, but that checkpoint happens after
    1062             :          *   the end of the scenario.
    1063             :          * - VACUUM to advance XID limits.
    1064             :          * - Consume ~2M XIDs, crossing the former xidWrapLimit.
    1065             :          * - Start, finish, and summarize a SERIALIZABLE transaction.
    1066             :          *   SerialAdd() declines to create the targetPage, because headPage
    1067             :          *   is not regarded as in the past relative to that targetPage.  The
    1068             :          *   transaction instigating the summarize fails in
    1069             :          *   SimpleLruReadPage().
    1070             :          */
    1071           0 :         truncateCutoffPage = serialControl->headPage;
    1072           0 :         serialControl->headPage = -1;
    1073             :     }
    1074             : 
    1075           0 :     LWLockRelease(SerialSLRULock);
    1076             : 
    1077             :     /* Truncate away pages that are no longer required */
    1078           0 :     SimpleLruTruncate(SerialSlruCtl, truncateCutoffPage);
    1079             : 
    1080             :     /*
    1081             :      * Write dirty SLRU pages to disk
    1082             :      *
    1083             :      * This is not actually necessary from a correctness point of view. We do
    1084             :      * it merely as a debugging aid.
    1085             :      *
    1086             :      * We're doing this after the truncation to avoid writing pages right
    1087             :      * before deleting the file in which they sit, which would be completely
    1088             :      * pointless.
    1089             :      */
    1090           0 :     SimpleLruWriteAll(SerialSlruCtl, true);
    1091             : }
    1092             : 
    1093             : /*------------------------------------------------------------------------*/
    1094             : 
    1095             : /*
    1096             :  * InitPredicateLocks -- Initialize the predicate locking data structures.
    1097             :  *
    1098             :  * This is called from CreateSharedMemoryAndSemaphores(), which see for
    1099             :  * more comments.  In the normal postmaster case, the shared hash tables
    1100             :  * are created here.  Backends inherit the pointers
    1101             :  * to the shared tables via fork().  In the EXEC_BACKEND case, each
    1102             :  * backend re-executes this code to obtain pointers to the already existing
    1103             :  * shared hash tables.
    1104             :  */
    1105             : void
    1106        1562 : InitPredicateLocks(void)
    1107             : {
    1108             :     HASHCTL     info;
    1109             :     long        max_table_size;
    1110             :     Size        requestSize;
    1111             :     bool        found;
    1112             : 
    1113             : #ifndef EXEC_BACKEND
    1114             :     Assert(!IsUnderPostmaster);
    1115             : #endif
    1116             : 
    1117             :     /*
    1118             :      * Compute size of predicate lock target hashtable. Note these
    1119             :      * calculations must agree with PredicateLockShmemSize!
    1120             :      */
    1121        1562 :     max_table_size = NPREDICATELOCKTARGETENTS();
    1122             : 
    1123             :     /*
    1124             :      * Allocate hash table for PREDICATELOCKTARGET structs.  This stores
    1125             :      * per-predicate-lock-target information.
    1126             :      */
    1127        1562 :     info.keysize = sizeof(PREDICATELOCKTARGETTAG);
    1128        1562 :     info.entrysize = sizeof(PREDICATELOCKTARGET);
    1129        1562 :     info.num_partitions = NUM_PREDICATELOCK_PARTITIONS;
    1130             : 
    1131        1562 :     PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
    1132             :                                             max_table_size,
    1133             :                                             max_table_size,
    1134             :                                             &info,
    1135             :                                             HASH_ELEM | HASH_BLOBS |
    1136             :                                             HASH_PARTITION | HASH_FIXED_SIZE);
    1137             : 
    1138             :     /*
    1139             :      * Reserve a dummy entry in the hash table; we use it to make sure there's
    1140             :      * always one entry available when we need to split or combine a page,
    1141             :      * because running out of space there could mean aborting a
    1142             :      * non-serializable transaction.
    1143             :      */
    1144        1562 :     if (!IsUnderPostmaster)
    1145             :     {
    1146        1562 :         (void) hash_search(PredicateLockTargetHash, &ScratchTargetTag,
    1147             :                            HASH_ENTER, &found);
    1148             :         Assert(!found);
    1149             :     }
    1150             : 
    1151             :     /* Pre-calculate the hash and partition lock of the scratch entry */
    1152        1562 :     ScratchTargetTagHash = PredicateLockTargetTagHashCode(&ScratchTargetTag);
    1153        1562 :     ScratchPartitionLock = PredicateLockHashPartitionLock(ScratchTargetTagHash);
    1154             : 
    1155             :     /*
    1156             :      * Allocate hash table for PREDICATELOCK structs.  This stores per
    1157             :      * xact-lock-of-a-target information.
    1158             :      */
    1159        1562 :     info.keysize = sizeof(PREDICATELOCKTAG);
    1160        1562 :     info.entrysize = sizeof(PREDICATELOCK);
    1161        1562 :     info.hash = predicatelock_hash;
    1162        1562 :     info.num_partitions = NUM_PREDICATELOCK_PARTITIONS;
    1163             : 
    1164             :     /* Assume an average of 2 xacts per target */
    1165        1562 :     max_table_size *= 2;
    1166             : 
    1167        1562 :     PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
    1168             :                                       max_table_size,
    1169             :                                       max_table_size,
    1170             :                                       &info,
    1171             :                                       HASH_ELEM | HASH_FUNCTION |
    1172             :                                       HASH_PARTITION | HASH_FIXED_SIZE);
    1173             : 
    1174             :     /*
    1175             :      * Compute size for serializable transaction hashtable. Note these
    1176             :      * calculations must agree with PredicateLockShmemSize!
    1177             :      */
    1178        1562 :     max_table_size = (MaxBackends + max_prepared_xacts);
    1179             : 
    1180             :     /*
    1181             :      * Allocate a list to hold information on transactions participating in
    1182             :      * predicate locking.
    1183             :      *
    1184             :      * Assume an average of 10 predicate locking transactions per backend.
    1185             :      * This allows aggressive cleanup while detail is present before data must
    1186             :      * be summarized for storage in SLRU and the "dummy" transaction.
    1187             :      */
    1188        1562 :     max_table_size *= 10;
    1189             : 
    1190        1562 :     PredXact = ShmemInitStruct("PredXactList",
    1191             :                                PredXactListDataSize,
    1192             :                                &found);
    1193             :     Assert(found == IsUnderPostmaster);
    1194        1562 :     if (!found)
    1195             :     {
    1196             :         int         i;
    1197             : 
    1198        1562 :         dlist_init(&PredXact->availableList);
    1199        1562 :         dlist_init(&PredXact->activeList);
    1200        1562 :         PredXact->SxactGlobalXmin = InvalidTransactionId;
    1201        1562 :         PredXact->SxactGlobalXminCount = 0;
    1202        1562 :         PredXact->WritableSxactCount = 0;
    1203        1562 :         PredXact->LastSxactCommitSeqNo = FirstNormalSerCommitSeqNo - 1;
    1204        1562 :         PredXact->CanPartialClearThrough = 0;
    1205        1562 :         PredXact->HavePartialClearedThrough = 0;
    1206        1562 :         requestSize = mul_size((Size) max_table_size,
    1207             :                                sizeof(SERIALIZABLEXACT));
    1208        1562 :         PredXact->element = ShmemAlloc(requestSize);
    1209             :         /* Add all elements to available list, clean. */
    1210        1562 :         memset(PredXact->element, 0, requestSize);
    1211     1319282 :         for (i = 0; i < max_table_size; i++)
    1212             :         {
    1213     1317720 :             LWLockInitialize(&PredXact->element[i].perXactPredicateListLock,
    1214             :                              LWTRANCHE_PER_XACT_PREDICATE_LIST);
    1215     1317720 :             dlist_push_tail(&PredXact->availableList, &PredXact->element[i].xactLink);
    1216             :         }
    1217        1562 :         PredXact->OldCommittedSxact = CreatePredXact();
    1218        1562 :         SetInvalidVirtualTransactionId(PredXact->OldCommittedSxact->vxid);
    1219        1562 :         PredXact->OldCommittedSxact->prepareSeqNo = 0;
    1220        1562 :         PredXact->OldCommittedSxact->commitSeqNo = 0;
    1221        1562 :         PredXact->OldCommittedSxact->SeqNo.lastCommitBeforeSnapshot = 0;
    1222        1562 :         dlist_init(&PredXact->OldCommittedSxact->outConflicts);
    1223        1562 :         dlist_init(&PredXact->OldCommittedSxact->inConflicts);
    1224        1562 :         dlist_init(&PredXact->OldCommittedSxact->predicateLocks);
    1225        1562 :         dlist_node_init(&PredXact->OldCommittedSxact->finishedLink);
    1226        1562 :         dlist_init(&PredXact->OldCommittedSxact->possibleUnsafeConflicts);
    1227        1562 :         PredXact->OldCommittedSxact->topXid = InvalidTransactionId;
    1228        1562 :         PredXact->OldCommittedSxact->finishedBefore = InvalidTransactionId;
    1229        1562 :         PredXact->OldCommittedSxact->xmin = InvalidTransactionId;
    1230        1562 :         PredXact->OldCommittedSxact->flags = SXACT_FLAG_COMMITTED;
    1231        1562 :         PredXact->OldCommittedSxact->pid = 0;
    1232        1562 :         PredXact->OldCommittedSxact->pgprocno = INVALID_PGPROCNO;
    1233             :     }
    1234             :     /* This never changes, so let's keep a local copy. */
    1235        1562 :     OldCommittedSxact = PredXact->OldCommittedSxact;
    1236             : 
    1237             :     /*
    1238             :      * Allocate hash table for SERIALIZABLEXID structs.  This stores per-xid
    1239             :      * information for serializable transactions which have accessed data.
    1240             :      */
    1241        1562 :     info.keysize = sizeof(SERIALIZABLEXIDTAG);
    1242        1562 :     info.entrysize = sizeof(SERIALIZABLEXID);
    1243             : 
    1244        1562 :     SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
    1245             :                                         max_table_size,
    1246             :                                         max_table_size,
    1247             :                                         &info,
    1248             :                                         HASH_ELEM | HASH_BLOBS |
    1249             :                                         HASH_FIXED_SIZE);
    1250             : 
    1251             :     /*
    1252             :      * Allocate space for tracking rw-conflicts in lists attached to the
    1253             :      * transactions.
    1254             :      *
    1255             :      * Assume an average of 5 conflicts per transaction.  Calculations suggest
    1256             :      * that this will prevent resource exhaustion in even the most pessimal
    1257             :      * loads up to max_connections = 200 with all 200 connections pounding the
    1258             :      * database with serializable transactions.  Beyond that, there may be
    1259             :      * occasional transactions canceled when trying to flag conflicts. That's
    1260             :      * probably OK.
    1261             :      */
    1262        1562 :     max_table_size *= 5;
    1263             : 
    1264        1562 :     RWConflictPool = ShmemInitStruct("RWConflictPool",
    1265             :                                      RWConflictPoolHeaderDataSize,
    1266             :                                      &found);
    1267             :     Assert(found == IsUnderPostmaster);
    1268        1562 :     if (!found)
    1269             :     {
    1270             :         int         i;
    1271             : 
    1272        1562 :         dlist_init(&RWConflictPool->availableList);
    1273        1562 :         requestSize = mul_size((Size) max_table_size,
    1274             :                                RWConflictDataSize);
    1275        1562 :         RWConflictPool->element = ShmemAlloc(requestSize);
    1276             :         /* Add all elements to available list, clean. */
    1277        1562 :         memset(RWConflictPool->element, 0, requestSize);
    1278     6590162 :         for (i = 0; i < max_table_size; i++)
    1279             :         {
    1280     6588600 :             dlist_push_tail(&RWConflictPool->availableList,
    1281     6588600 :                             &RWConflictPool->element[i].outLink);
    1282             :         }
    1283             :     }
    1284             : 
    1285             :     /*
    1286             :      * Create or attach to the header for the list of finished serializable
    1287             :      * transactions.
    1288             :      */
    1289        1562 :     FinishedSerializableTransactions = (dlist_head *)
    1290        1562 :         ShmemInitStruct("FinishedSerializableTransactions",
    1291             :                         sizeof(dlist_head),
    1292             :                         &found);
    1293             :     Assert(found == IsUnderPostmaster);
    1294        1562 :     if (!found)
    1295        1562 :         dlist_init(FinishedSerializableTransactions);
    1296             : 
    1297             :     /*
    1298             :      * Initialize the SLRU storage for old committed serializable
    1299             :      * transactions.
    1300             :      */
    1301        1562 :     SerialInit();
    1302        1562 : }
    1303             : 
    1304             : /*
    1305             :  * Estimate shared-memory space used for predicate lock table
    1306             :  */
    1307             : Size
    1308        2934 : PredicateLockShmemSize(void)
    1309             : {
    1310        2934 :     Size        size = 0;
    1311             :     long        max_table_size;
    1312             : 
    1313             :     /* predicate lock target hash table */
    1314        2934 :     max_table_size = NPREDICATELOCKTARGETENTS();
    1315        2934 :     size = add_size(size, hash_estimate_size(max_table_size,
    1316             :                                              sizeof(PREDICATELOCKTARGET)));
    1317             : 
    1318             :     /* predicate lock hash table */
    1319        2934 :     max_table_size *= 2;
    1320        2934 :     size = add_size(size, hash_estimate_size(max_table_size,
    1321             :                                              sizeof(PREDICATELOCK)));
    1322             : 
    1323             :     /*
    1324             :      * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
    1325             :      * margin.
    1326             :      */
    1327        2934 :     size = add_size(size, size / 10);
    1328             : 
    1329             :     /* transaction list */
    1330        2934 :     max_table_size = MaxBackends + max_prepared_xacts;
    1331        2934 :     max_table_size *= 10;
    1332        2934 :     size = add_size(size, PredXactListDataSize);
    1333        2934 :     size = add_size(size, mul_size((Size) max_table_size,
    1334             :                                    sizeof(SERIALIZABLEXACT)));
    1335             : 
    1336             :     /* transaction xid table */
    1337        2934 :     size = add_size(size, hash_estimate_size(max_table_size,
    1338             :                                              sizeof(SERIALIZABLEXID)));
    1339             : 
    1340             :     /* rw-conflict pool */
    1341        2934 :     max_table_size *= 5;
    1342        2934 :     size = add_size(size, RWConflictPoolHeaderDataSize);
    1343        2934 :     size = add_size(size, mul_size((Size) max_table_size,
    1344             :                                    RWConflictDataSize));
    1345             : 
    1346             :     /* Head for list of finished serializable transactions. */
    1347        2934 :     size = add_size(size, sizeof(dlist_head));
    1348             : 
    1349             :     /* Shared memory structures for SLRU tracking of old committed xids. */
    1350        2934 :     size = add_size(size, sizeof(SerialControlData));
    1351        2934 :     size = add_size(size, SimpleLruShmemSize(NUM_SERIAL_BUFFERS, 0));
    1352             : 
    1353        2934 :     return size;
    1354             : }
    1355             : 
    1356             : 
    1357             : /*
    1358             :  * Compute the hash code associated with a PREDICATELOCKTAG.
    1359             :  *
    1360             :  * Because we want to use just one set of partition locks for both the
    1361             :  * PREDICATELOCKTARGET and PREDICATELOCK hash tables, we have to make sure
    1362             :  * that PREDICATELOCKs fall into the same partition number as their
    1363             :  * associated PREDICATELOCKTARGETs.  dynahash.c expects the partition number
    1364             :  * to be the low-order bits of the hash code, and therefore a
    1365             :  * PREDICATELOCKTAG's hash code must have the same low-order bits as the
    1366             :  * associated PREDICATELOCKTARGETTAG's hash code.  We achieve this with this
    1367             :  * specialized hash function.
    1368             :  */
    1369             : static uint32
    1370           0 : predicatelock_hash(const void *key, Size keysize)
    1371             : {
    1372           0 :     const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
    1373             :     uint32      targethash;
    1374             : 
    1375             :     Assert(keysize == sizeof(PREDICATELOCKTAG));
    1376             : 
    1377             :     /* Look into the associated target object, and compute its hash code */
    1378           0 :     targethash = PredicateLockTargetTagHashCode(&predicatelocktag->myTarget->tag);
    1379             : 
    1380           0 :     return PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash);
    1381             : }
    1382             : 
    1383             : 
    1384             : /*
    1385             :  * GetPredicateLockStatusData
    1386             :  *      Return a table containing the internal state of the predicate
    1387             :  *      lock manager for use in pg_lock_status.
    1388             :  *
    1389             :  * Like GetLockStatusData, this function tries to hold the partition LWLocks
    1390             :  * for as short a time as possible by returning two arrays that simply
    1391             :  * contain the PREDICATELOCKTARGETTAG and SERIALIZABLEXACT for each lock
    1392             :  * table entry. Multiple copies of the same PREDICATELOCKTARGETTAG and
    1393             :  * SERIALIZABLEXACT will likely appear.
    1394             :  */
    1395             : PredicateLockData *
    1396         508 : GetPredicateLockStatusData(void)
    1397             : {
    1398             :     PredicateLockData *data;
    1399             :     int         i;
    1400             :     int         els,
    1401             :                 el;
    1402             :     HASH_SEQ_STATUS seqstat;
    1403             :     PREDICATELOCK *predlock;
    1404             : 
    1405         508 :     data = (PredicateLockData *) palloc(sizeof(PredicateLockData));
    1406             : 
    1407             :     /*
    1408             :      * To ensure consistency, take simultaneous locks on all partition locks
    1409             :      * in ascending order, then SerializableXactHashLock.
    1410             :      */
    1411        8636 :     for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
    1412        8128 :         LWLockAcquire(PredicateLockHashPartitionLockByIndex(i), LW_SHARED);
    1413         508 :     LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    1414             : 
    1415             :     /* Get number of locks and allocate appropriately-sized arrays. */
    1416         508 :     els = hash_get_num_entries(PredicateLockHash);
    1417         508 :     data->nelements = els;
    1418         508 :     data->locktags = (PREDICATELOCKTARGETTAG *)
    1419         508 :         palloc(sizeof(PREDICATELOCKTARGETTAG) * els);
    1420         508 :     data->xacts = (SERIALIZABLEXACT *)
    1421         508 :         palloc(sizeof(SERIALIZABLEXACT) * els);
    1422             : 
    1423             : 
    1424             :     /* Scan through PredicateLockHash and copy contents */
    1425         508 :     hash_seq_init(&seqstat, PredicateLockHash);
    1426             : 
    1427         508 :     el = 0;
    1428             : 
    1429         514 :     while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
    1430             :     {
    1431           6 :         data->locktags[el] = predlock->tag.myTarget->tag;
    1432           6 :         data->xacts[el] = *predlock->tag.myXact;
    1433           6 :         el++;
    1434             :     }
    1435             : 
    1436             :     Assert(el == els);
    1437             : 
    1438             :     /* Release locks in reverse order */
    1439         508 :     LWLockRelease(SerializableXactHashLock);
    1440        8636 :     for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
    1441        8128 :         LWLockRelease(PredicateLockHashPartitionLockByIndex(i));
    1442             : 
    1443         508 :     return data;
    1444             : }
    1445             : 
    1446             : /*
    1447             :  * Free up shared memory structures by pushing the oldest sxact (the one at
    1448             :  * the front of the SummarizeOldestCommittedSxact queue) into summary form.
    1449             :  * Each call will free exactly one SERIALIZABLEXACT structure and may also
    1450             :  * free one or more of these structures: SERIALIZABLEXID, PREDICATELOCK,
    1451             :  * PREDICATELOCKTARGET, RWConflictData.
    1452             :  */
    1453             : static void
    1454           0 : SummarizeOldestCommittedSxact(void)
    1455             : {
    1456             :     SERIALIZABLEXACT *sxact;
    1457             : 
    1458           0 :     LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
    1459             : 
    1460             :     /*
    1461             :      * This function is only called if there are no sxact slots available.
    1462             :      * Some of them must belong to old, already-finished transactions, so
    1463             :      * there should be something in FinishedSerializableTransactions list that
    1464             :      * we can summarize. However, there's a race condition: while we were not
    1465             :      * holding any locks, a transaction might have ended and cleaned up all
    1466             :      * the finished sxact entries already, freeing up their sxact slots. In
    1467             :      * that case, we have nothing to do here. The caller will find one of the
    1468             :      * slots released by the other backend when it retries.
    1469             :      */
    1470           0 :     if (dlist_is_empty(FinishedSerializableTransactions))
    1471             :     {
    1472           0 :         LWLockRelease(SerializableFinishedListLock);
    1473           0 :         return;
    1474             :     }
    1475             : 
    1476             :     /*
    1477             :      * Grab the first sxact off the finished list -- this will be the earliest
    1478             :      * commit.  Remove it from the list.
    1479             :      */
    1480           0 :     sxact = dlist_head_element(SERIALIZABLEXACT, finishedLink,
    1481             :                                FinishedSerializableTransactions);
    1482           0 :     dlist_delete_thoroughly(&sxact->finishedLink);
    1483             : 
    1484             :     /* Add to SLRU summary information. */
    1485           0 :     if (TransactionIdIsValid(sxact->topXid) && !SxactIsReadOnly(sxact))
    1486           0 :         SerialAdd(sxact->topXid, SxactHasConflictOut(sxact)
    1487             :                   ? sxact->SeqNo.earliestOutConflictCommit : InvalidSerCommitSeqNo);
    1488             : 
    1489             :     /* Summarize and release the detail. */
    1490           0 :     ReleaseOneSerializableXact(sxact, false, true);
    1491             : 
    1492           0 :     LWLockRelease(SerializableFinishedListLock);
    1493             : }
    1494             : 
    1495             : /*
    1496             :  * GetSafeSnapshot
    1497             :  *      Obtain and register a snapshot for a READ ONLY DEFERRABLE
    1498             :  *      transaction. Ensures that the snapshot is "safe", i.e. a
    1499             :  *      read-only transaction running on it can execute serializably
    1500             :  *      without further checks. This requires waiting for concurrent
    1501             :  *      transactions to complete, and retrying with a new snapshot if
    1502             :  *      one of them could possibly create a conflict.
    1503             :  *
    1504             :  *      As with GetSerializableTransactionSnapshot (which this is a subroutine
    1505             :  *      for), the passed-in Snapshot pointer should reference a static data
    1506             :  *      area that can safely be passed to GetSnapshotData.
    1507             :  */
    1508             : static Snapshot
    1509          10 : GetSafeSnapshot(Snapshot origSnapshot)
    1510             : {
    1511             :     Snapshot    snapshot;
    1512             : 
    1513             :     Assert(XactReadOnly && XactDeferrable);
    1514             : 
    1515             :     while (true)
    1516             :     {
    1517             :         /*
    1518             :          * GetSerializableTransactionSnapshotInt is going to call
    1519             :          * GetSnapshotData, so we need to provide it the static snapshot area
    1520             :          * our caller passed to us.  The pointer returned is actually the same
    1521             :          * one passed to it, but we avoid assuming that here.
    1522             :          */
    1523          10 :         snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
    1524             :                                                          NULL, InvalidPid);
    1525             : 
    1526          10 :         if (MySerializableXact == InvalidSerializableXact)
    1527           8 :             return snapshot;    /* no concurrent r/w xacts; it's safe */
    1528             : 
    1529           2 :         LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    1530             : 
    1531             :         /*
    1532             :          * Wait for concurrent transactions to finish. Stop early if one of
    1533             :          * them marked us as conflicted.
    1534             :          */
    1535           2 :         MySerializableXact->flags |= SXACT_FLAG_DEFERRABLE_WAITING;
    1536           4 :         while (!(dlist_is_empty(&MySerializableXact->possibleUnsafeConflicts) ||
    1537           2 :                  SxactIsROUnsafe(MySerializableXact)))
    1538             :         {
    1539           2 :             LWLockRelease(SerializableXactHashLock);
    1540           2 :             ProcWaitForSignal(WAIT_EVENT_SAFE_SNAPSHOT);
    1541           2 :             LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    1542             :         }
    1543           2 :         MySerializableXact->flags &= ~SXACT_FLAG_DEFERRABLE_WAITING;
    1544             : 
    1545           2 :         if (!SxactIsROUnsafe(MySerializableXact))
    1546             :         {
    1547           0 :             LWLockRelease(SerializableXactHashLock);
    1548           0 :             break;              /* success */
    1549             :         }
    1550             : 
    1551           2 :         LWLockRelease(SerializableXactHashLock);
    1552             : 
    1553             :         /* else, need to retry... */
    1554           2 :         ereport(DEBUG2,
    1555             :                 (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
    1556             :                  errmsg_internal("deferrable snapshot was unsafe; trying a new one")));
    1557           2 :         ReleasePredicateLocks(false, false);
    1558             :     }
    1559             : 
    1560             :     /*
    1561             :      * Now we have a safe snapshot, so we don't need to do any further checks.
    1562             :      */
    1563             :     Assert(SxactIsROSafe(MySerializableXact));
    1564           0 :     ReleasePredicateLocks(false, true);
    1565             : 
    1566           0 :     return snapshot;
    1567             : }
    1568             : 
    1569             : /*
    1570             :  * GetSafeSnapshotBlockingPids
    1571             :  *      If the specified process is currently blocked in GetSafeSnapshot,
    1572             :  *      write the process IDs of all processes that it is blocked by
    1573             :  *      into the caller-supplied buffer output[].  The list is truncated at
    1574             :  *      output_size, and the number of PIDs written into the buffer is
    1575             :  *      returned.  Returns zero if the given PID is not currently blocked
    1576             :  *      in GetSafeSnapshot.
    1577             :  */
    1578             : int
    1579         804 : GetSafeSnapshotBlockingPids(int blocked_pid, int *output, int output_size)
    1580             : {
    1581         804 :     int         num_written = 0;
    1582             :     dlist_iter  iter;
    1583         804 :     SERIALIZABLEXACT *blocking_sxact = NULL;
    1584             : 
    1585         804 :     LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    1586             : 
    1587             :     /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
    1588        2146 :     dlist_foreach(iter, &PredXact->activeList)
    1589             :     {
    1590        1710 :         SERIALIZABLEXACT *sxact =
    1591        1710 :             dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
    1592             : 
    1593        1710 :         if (sxact->pid == blocked_pid)
    1594             :         {
    1595         368 :             blocking_sxact = sxact;
    1596         368 :             break;
    1597             :         }
    1598             :     }
    1599             : 
    1600             :     /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
    1601         804 :     if (blocking_sxact != NULL && SxactIsDeferrableWaiting(blocking_sxact))
    1602             :     {
    1603             :         /* Traverse the list of possible unsafe conflicts collecting PIDs. */
    1604           4 :         dlist_foreach(iter, &blocking_sxact->possibleUnsafeConflicts)
    1605             :         {
    1606           4 :             RWConflict  possibleUnsafeConflict =
    1607           4 :                 dlist_container(RWConflictData, inLink, iter.cur);
    1608             : 
    1609           4 :             output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
    1610             : 
    1611           4 :             if (num_written >= output_size)
    1612           4 :                 break;
    1613             :         }
    1614             :     }
    1615             : 
    1616         804 :     LWLockRelease(SerializableXactHashLock);
    1617             : 
    1618         804 :     return num_written;
    1619             : }
    1620             : 
    1621             : /*
    1622             :  * Acquire a snapshot that can be used for the current transaction.
    1623             :  *
    1624             :  * Make sure we have a SERIALIZABLEXACT reference in MySerializableXact.
    1625             :  * It should be current for this process and be contained in PredXact.
    1626             :  *
    1627             :  * The passed-in Snapshot pointer should reference a static data area that
    1628             :  * can safely be passed to GetSnapshotData.  The return value is actually
    1629             :  * always this same pointer; no new snapshot data structure is allocated
    1630             :  * within this function.
    1631             :  */
    1632             : Snapshot
    1633        3280 : GetSerializableTransactionSnapshot(Snapshot snapshot)
    1634             : {
    1635             :     Assert(IsolationIsSerializable());
    1636             : 
    1637             :     /*
    1638             :      * Can't use serializable mode while recovery is still active, as it is,
    1639             :      * for example, on a hot standby.  We could get here despite the check in
    1640             :      * check_transaction_isolation() if default_transaction_isolation is set
    1641             :      * to serializable, so phrase the hint accordingly.
    1642             :      */
    1643        3280 :     if (RecoveryInProgress())
    1644           0 :         ereport(ERROR,
    1645             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1646             :                  errmsg("cannot use serializable mode in a hot standby"),
    1647             :                  errdetail("default_transaction_isolation is set to \"serializable\"."),
    1648             :                  errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
    1649             : 
    1650             :     /*
    1651             :      * A special optimization is available for SERIALIZABLE READ ONLY
    1652             :      * DEFERRABLE transactions -- we can wait for a suitable snapshot and
    1653             :      * thereby avoid all SSI overhead once it's running.
    1654             :      */
    1655        3280 :     if (XactReadOnly && XactDeferrable)
    1656           8 :         return GetSafeSnapshot(snapshot);
    1657             : 
    1658        3272 :     return GetSerializableTransactionSnapshotInt(snapshot,
    1659             :                                                  NULL, InvalidPid);
    1660             : }
    1661             : 
    1662             : /*
    1663             :  * Import a snapshot to be used for the current transaction.
    1664             :  *
    1665             :  * This is nearly the same as GetSerializableTransactionSnapshot, except that
    1666             :  * we don't take a new snapshot, but rather use the data we're handed.
    1667             :  *
    1668             :  * The caller must have verified that the snapshot came from a serializable
    1669             :  * transaction; and if we're read-write, the source transaction must not be
    1670             :  * read-only.
    1671             :  */
    1672             : void
    1673          26 : SetSerializableTransactionSnapshot(Snapshot snapshot,
    1674             :                                    VirtualTransactionId *sourcevxid,
    1675             :                                    int sourcepid)
    1676             : {
    1677             :     Assert(IsolationIsSerializable());
    1678             : 
    1679             :     /*
    1680             :      * If this is called by parallel.c in a parallel worker, we don't want to
    1681             :      * create a SERIALIZABLEXACT just yet because the leader's
    1682             :      * SERIALIZABLEXACT will be installed with AttachSerializableXact().  We
    1683             :      * also don't want to reject SERIALIZABLE READ ONLY DEFERRABLE in this
    1684             :      * case, because the leader has already determined that the snapshot it
    1685             :      * has passed us is safe.  So there is nothing for us to do.
    1686             :      */
    1687          26 :     if (IsParallelWorker())
    1688          26 :         return;
    1689             : 
    1690             :     /*
    1691             :      * We do not allow SERIALIZABLE READ ONLY DEFERRABLE transactions to
    1692             :      * import snapshots, since there's no way to wait for a safe snapshot when
    1693             :      * we're using the snap we're told to.  (XXX instead of throwing an error,
    1694             :      * we could just ignore the XactDeferrable flag?)
    1695             :      */
    1696           0 :     if (XactReadOnly && XactDeferrable)
    1697           0 :         ereport(ERROR,
    1698             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1699             :                  errmsg("a snapshot-importing transaction must not be READ ONLY DEFERRABLE")));
    1700             : 
    1701           0 :     (void) GetSerializableTransactionSnapshotInt(snapshot, sourcevxid,
    1702             :                                                  sourcepid);
    1703             : }
    1704             : 
    1705             : /*
    1706             :  * Guts of GetSerializableTransactionSnapshot
    1707             :  *
    1708             :  * If sourcevxid is valid, this is actually an import operation and we should
    1709             :  * skip calling GetSnapshotData, because the snapshot contents are already
    1710             :  * loaded up.  HOWEVER: to avoid race conditions, we must check that the
    1711             :  * source xact is still running after we acquire SerializableXactHashLock.
    1712             :  * We do that by calling ProcArrayInstallImportedXmin.
    1713             :  */
    1714             : static Snapshot
    1715        3282 : GetSerializableTransactionSnapshotInt(Snapshot snapshot,
    1716             :                                       VirtualTransactionId *sourcevxid,
    1717             :                                       int sourcepid)
    1718             : {
    1719             :     PGPROC     *proc;
    1720             :     VirtualTransactionId vxid;
    1721             :     SERIALIZABLEXACT *sxact,
    1722             :                *othersxact;
    1723             : 
    1724             :     /* We only do this for serializable transactions.  Once. */
    1725             :     Assert(MySerializableXact == InvalidSerializableXact);
    1726             : 
    1727             :     Assert(!RecoveryInProgress());
    1728             : 
    1729             :     /*
    1730             :      * Since all parts of a serializable transaction must use the same
    1731             :      * snapshot, it is too late to establish one after a parallel operation
    1732             :      * has begun.
    1733             :      */
    1734        3282 :     if (IsInParallelMode())
    1735           0 :         elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
    1736             : 
    1737        3282 :     proc = MyProc;
    1738             :     Assert(proc != NULL);
    1739        3282 :     GET_VXID_FROM_PGPROC(vxid, *proc);
    1740             : 
    1741             :     /*
    1742             :      * First we get the sxact structure, which may involve looping and access
    1743             :      * to the "finished" list to free a structure for use.
    1744             :      *
    1745             :      * We must hold SerializableXactHashLock when taking/checking the snapshot
    1746             :      * to avoid race conditions, for much the same reasons that
    1747             :      * GetSnapshotData takes the ProcArrayLock.  Since we might have to
    1748             :      * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
    1749             :      * this means we have to create the sxact first, which is a bit annoying
    1750             :      * (in particular, an elog(ERROR) in procarray.c would cause us to leak
    1751             :      * the sxact).  Consider refactoring to avoid this.
    1752             :      */
    1753             : #ifdef TEST_SUMMARIZE_SERIAL
    1754             :     SummarizeOldestCommittedSxact();
    1755             : #endif
    1756        3282 :     LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    1757             :     do
    1758             :     {
    1759        3282 :         sxact = CreatePredXact();
    1760             :         /* If null, push out committed sxact to SLRU summary & retry. */
    1761        3282 :         if (!sxact)
    1762             :         {
    1763           0 :             LWLockRelease(SerializableXactHashLock);
    1764           0 :             SummarizeOldestCommittedSxact();
    1765           0 :             LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    1766             :         }
    1767        3282 :     } while (!sxact);
    1768             : 
    1769             :     /* Get the snapshot, or check that it's safe to use */
    1770        3282 :     if (!sourcevxid)
    1771        3282 :         snapshot = GetSnapshotData(snapshot);
    1772           0 :     else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid))
    1773             :     {
    1774           0 :         ReleasePredXact(sxact);
    1775           0 :         LWLockRelease(SerializableXactHashLock);
    1776           0 :         ereport(ERROR,
    1777             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    1778             :                  errmsg("could not import the requested snapshot"),
    1779             :                  errdetail("The source process with PID %d is not running anymore.",
    1780             :                            sourcepid)));
    1781             :     }
    1782             : 
    1783             :     /*
    1784             :      * If there are no serializable transactions which are not read-only, we
    1785             :      * can "opt out" of predicate locking and conflict checking for a
    1786             :      * read-only transaction.
    1787             :      *
    1788             :      * The reason this is safe is that a read-only transaction can only become
    1789             :      * part of a dangerous structure if it overlaps a writable transaction
    1790             :      * which in turn overlaps a writable transaction which committed before
    1791             :      * the read-only transaction started.  A new writable transaction can
    1792             :      * overlap this one, but it can't meet the other condition of overlapping
    1793             :      * a transaction which committed before this one started.
    1794             :      */
    1795        3282 :     if (XactReadOnly && PredXact->WritableSxactCount == 0)
    1796             :     {
    1797         224 :         ReleasePredXact(sxact);
    1798         224 :         LWLockRelease(SerializableXactHashLock);
    1799         224 :         return snapshot;
    1800             :     }
    1801             : 
    1802             :     /* Initialize the structure. */
    1803        3058 :     sxact->vxid = vxid;
    1804        3058 :     sxact->SeqNo.lastCommitBeforeSnapshot = PredXact->LastSxactCommitSeqNo;
    1805        3058 :     sxact->prepareSeqNo = InvalidSerCommitSeqNo;
    1806        3058 :     sxact->commitSeqNo = InvalidSerCommitSeqNo;
    1807        3058 :     dlist_init(&(sxact->outConflicts));
    1808        3058 :     dlist_init(&(sxact->inConflicts));
    1809        3058 :     dlist_init(&(sxact->possibleUnsafeConflicts));
    1810        3058 :     sxact->topXid = GetTopTransactionIdIfAny();
    1811        3058 :     sxact->finishedBefore = InvalidTransactionId;
    1812        3058 :     sxact->xmin = snapshot->xmin;
    1813        3058 :     sxact->pid = MyProcPid;
    1814        3058 :     sxact->pgprocno = MyProc->pgprocno;
    1815        3058 :     dlist_init(&sxact->predicateLocks);
    1816        3058 :     dlist_node_init(&sxact->finishedLink);
    1817        3058 :     sxact->flags = 0;
    1818        3058 :     if (XactReadOnly)
    1819             :     {
    1820             :         dlist_iter  iter;
    1821             : 
    1822         212 :         sxact->flags |= SXACT_FLAG_READ_ONLY;
    1823             : 
    1824             :         /*
    1825             :          * Register all concurrent r/w transactions as possible conflicts; if
    1826             :          * all of them commit without any outgoing conflicts to earlier
    1827             :          * transactions then this snapshot can be deemed safe (and we can run
    1828             :          * without tracking predicate locks).
    1829             :          */
    1830         928 :         dlist_foreach(iter, &PredXact->activeList)
    1831             :         {
    1832         716 :             othersxact = dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
    1833             : 
    1834         716 :             if (!SxactIsCommitted(othersxact)
    1835         478 :                 && !SxactIsDoomed(othersxact)
    1836         478 :                 && !SxactIsReadOnly(othersxact))
    1837             :             {
    1838         264 :                 SetPossibleUnsafeConflict(sxact, othersxact);
    1839             :             }
    1840             :         }
    1841             : 
    1842             :         /*
    1843             :          * If we didn't find any possibly unsafe conflicts because every
    1844             :          * uncommitted writable transaction turned out to be doomed, then we
    1845             :          * can "opt out" immediately.  See comments above the earlier check
    1846             :          * for PredXact->WritableSxactCount == 0.
    1847             :          */
    1848         212 :         if (dlist_is_empty(&sxact->possibleUnsafeConflicts))
    1849             :         {
    1850           0 :             ReleasePredXact(sxact);
    1851           0 :             LWLockRelease(SerializableXactHashLock);
    1852           0 :             return snapshot;
    1853             :         }
    1854             :     }
    1855             :     else
    1856             :     {
    1857        2846 :         ++(PredXact->WritableSxactCount);
    1858             :         Assert(PredXact->WritableSxactCount <=
    1859             :                (MaxBackends + max_prepared_xacts));
    1860             :     }
    1861             : 
    1862             :     /* Maintain serializable global xmin info. */
    1863        3058 :     if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
    1864             :     {
    1865             :         Assert(PredXact->SxactGlobalXminCount == 0);
    1866        1682 :         PredXact->SxactGlobalXmin = snapshot->xmin;
    1867        1682 :         PredXact->SxactGlobalXminCount = 1;
    1868        1682 :         SerialSetActiveSerXmin(snapshot->xmin);
    1869             :     }
    1870        1376 :     else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
    1871             :     {
    1872             :         Assert(PredXact->SxactGlobalXminCount > 0);
    1873        1308 :         PredXact->SxactGlobalXminCount++;
    1874             :     }
    1875             :     else
    1876             :     {
    1877             :         Assert(TransactionIdFollows(snapshot->xmin, PredXact->SxactGlobalXmin));
    1878             :     }
    1879             : 
    1880        3058 :     MySerializableXact = sxact;
    1881        3058 :     MyXactDidWrite = false;     /* haven't written anything yet */
    1882             : 
    1883        3058 :     LWLockRelease(SerializableXactHashLock);
    1884             : 
    1885        3058 :     CreateLocalPredicateLockHash();
    1886             : 
    1887        3058 :     return snapshot;
    1888             : }
    1889             : 
    1890             : static void
    1891        3084 : CreateLocalPredicateLockHash(void)
    1892             : {
    1893             :     HASHCTL     hash_ctl;
    1894             : 
    1895             :     /* Initialize the backend-local hash table of parent locks */
    1896             :     Assert(LocalPredicateLockHash == NULL);
    1897        3084 :     hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
    1898        3084 :     hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
    1899        3084 :     LocalPredicateLockHash = hash_create("Local predicate lock",
    1900             :                                          max_predicate_locks_per_xact,
    1901             :                                          &hash_ctl,
    1902             :                                          HASH_ELEM | HASH_BLOBS);
    1903        3084 : }
    1904             : 
    1905             : /*
    1906             :  * Register the top level XID in SerializableXidHash.
    1907             :  * Also store it for easy reference in MySerializableXact.
    1908             :  */
    1909             : void
    1910      203894 : RegisterPredicateLockingXid(TransactionId xid)
    1911             : {
    1912             :     SERIALIZABLEXIDTAG sxidtag;
    1913             :     SERIALIZABLEXID *sxid;
    1914             :     bool        found;
    1915             : 
    1916             :     /*
    1917             :      * If we're not tracking predicate lock data for this transaction, we
    1918             :      * should ignore the request and return quickly.
    1919             :      */
    1920      203894 :     if (MySerializableXact == InvalidSerializableXact)
    1921      201368 :         return;
    1922             : 
    1923             :     /* We should have a valid XID and be at the top level. */
    1924             :     Assert(TransactionIdIsValid(xid));
    1925             : 
    1926        2526 :     LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    1927             : 
    1928             :     /* This should only be done once per transaction. */
    1929             :     Assert(MySerializableXact->topXid == InvalidTransactionId);
    1930             : 
    1931        2526 :     MySerializableXact->topXid = xid;
    1932             : 
    1933        2526 :     sxidtag.xid = xid;
    1934        2526 :     sxid = (SERIALIZABLEXID *) hash_search(SerializableXidHash,
    1935             :                                            &sxidtag,
    1936             :                                            HASH_ENTER, &found);
    1937             :     Assert(!found);
    1938             : 
    1939             :     /* Initialize the structure. */
    1940        2526 :     sxid->myXact = MySerializableXact;
    1941        2526 :     LWLockRelease(SerializableXactHashLock);
    1942             : }
    1943             : 
    1944             : 
    1945             : /*
    1946             :  * Check whether there are any predicate locks held by any transaction
    1947             :  * for the page at the given block number.
    1948             :  *
    1949             :  * Note that the transaction may be completed but not yet subject to
    1950             :  * cleanup due to overlapping serializable transactions.  This must
    1951             :  * return valid information regardless of transaction isolation level.
    1952             :  *
    1953             :  * Also note that this doesn't check for a conflicting relation lock,
    1954             :  * just a lock specifically on the given page.
    1955             :  *
    1956             :  * One use is to support proper behavior during GiST index vacuum.
    1957             :  */
    1958             : bool
    1959           0 : PageIsPredicateLocked(Relation relation, BlockNumber blkno)
    1960             : {
    1961             :     PREDICATELOCKTARGETTAG targettag;
    1962             :     uint32      targettaghash;
    1963             :     LWLock     *partitionLock;
    1964             :     PREDICATELOCKTARGET *target;
    1965             : 
    1966           0 :     SET_PREDICATELOCKTARGETTAG_PAGE(targettag,
    1967             :                                     relation->rd_locator.dbOid,
    1968             :                                     relation->rd_id,
    1969             :                                     blkno);
    1970             : 
    1971           0 :     targettaghash = PredicateLockTargetTagHashCode(&targettag);
    1972           0 :     partitionLock = PredicateLockHashPartitionLock(targettaghash);
    1973           0 :     LWLockAcquire(partitionLock, LW_SHARED);
    1974             :     target = (PREDICATELOCKTARGET *)
    1975           0 :         hash_search_with_hash_value(PredicateLockTargetHash,
    1976             :                                     &targettag, targettaghash,
    1977             :                                     HASH_FIND, NULL);
    1978           0 :     LWLockRelease(partitionLock);
    1979             : 
    1980           0 :     return (target != NULL);
    1981             : }
    1982             : 
    1983             : 
    1984             : /*
    1985             :  * Check whether a particular lock is held by this transaction.
    1986             :  *
    1987             :  * Important note: this function may return false even if the lock is
    1988             :  * being held, because it uses the local lock table which is not
    1989             :  * updated if another transaction modifies our lock list (e.g. to
    1990             :  * split an index page). It can also return true when a coarser
    1991             :  * granularity lock that covers this target is being held. Be careful
    1992             :  * to only use this function in circumstances where such errors are
    1993             :  * acceptable!
    1994             :  */
    1995             : static bool
    1996      154388 : PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
    1997             : {
    1998             :     LOCALPREDICATELOCK *lock;
    1999             : 
    2000             :     /* check local hash table */
    2001      154388 :     lock = (LOCALPREDICATELOCK *) hash_search(LocalPredicateLockHash,
    2002             :                                               targettag,
    2003             :                                               HASH_FIND, NULL);
    2004             : 
    2005      154388 :     if (!lock)
    2006       60178 :         return false;
    2007             : 
    2008             :     /*
    2009             :      * Found entry in the table, but still need to check whether it's actually
    2010             :      * held -- it could just be a parent of some held lock.
    2011             :      */
    2012       94210 :     return lock->held;
    2013             : }
    2014             : 
    2015             : /*
    2016             :  * Return the parent lock tag in the lock hierarchy: the next coarser
    2017             :  * lock that covers the provided tag.
    2018             :  *
    2019             :  * Returns true and sets *parent to the parent tag if one exists,
    2020             :  * returns false if none exists.
    2021             :  */
    2022             : static bool
    2023       90298 : GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag,
    2024             :                           PREDICATELOCKTARGETTAG *parent)
    2025             : {
    2026       90298 :     switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
    2027             :     {
    2028       19600 :         case PREDLOCKTAG_RELATION:
    2029             :             /* relation locks have no parent lock */
    2030       19600 :             return false;
    2031             : 
    2032       16832 :         case PREDLOCKTAG_PAGE:
    2033             :             /* parent lock is relation lock */
    2034       16832 :             SET_PREDICATELOCKTARGETTAG_RELATION(*parent,
    2035             :                                                 GET_PREDICATELOCKTARGETTAG_DB(*tag),
    2036             :                                                 GET_PREDICATELOCKTARGETTAG_RELATION(*tag));
    2037             : 
    2038       16832 :             return true;
    2039             : 
    2040       53866 :         case PREDLOCKTAG_TUPLE:
    2041             :             /* parent lock is page lock */
    2042       53866 :             SET_PREDICATELOCKTARGETTAG_PAGE(*parent,
    2043             :                                             GET_PREDICATELOCKTARGETTAG_DB(*tag),
    2044             :                                             GET_PREDICATELOCKTARGETTAG_RELATION(*tag),
    2045             :                                             GET_PREDICATELOCKTARGETTAG_PAGE(*tag));
    2046       53866 :             return true;
    2047             :     }
    2048             : 
    2049             :     /* not reachable */
    2050             :     Assert(false);
    2051           0 :     return false;
    2052             : }
    2053             : 
    2054             : /*
    2055             :  * Check whether the lock we are considering is already covered by a
    2056             :  * coarser lock for our transaction.
    2057             :  *
    2058             :  * Like PredicateLockExists, this function might return a false
    2059             :  * negative, but it will never return a false positive.
    2060             :  */
    2061             : static bool
    2062       52062 : CoarserLockCovers(const PREDICATELOCKTARGETTAG *newtargettag)
    2063             : {
    2064             :     PREDICATELOCKTARGETTAG targettag,
    2065             :                 parenttag;
    2066             : 
    2067       52062 :     targettag = *newtargettag;
    2068             : 
    2069             :     /* check parents iteratively until no more */
    2070       62830 :     while (GetParentPredicateLockTag(&targettag, &parenttag))
    2071             :     {
    2072       54410 :         targettag = parenttag;
    2073       54410 :         if (PredicateLockExists(&targettag))
    2074       43642 :             return true;
    2075             :     }
    2076             : 
    2077             :     /* no more parents to check; lock is not covered */
    2078        8420 :     return false;
    2079             : }
    2080             : 
    2081             : /*
    2082             :  * Remove the dummy entry from the predicate lock target hash, to free up some
    2083             :  * scratch space. The caller must be holding SerializablePredicateListLock,
    2084             :  * and must restore the entry with RestoreScratchTarget() before releasing the
    2085             :  * lock.
    2086             :  *
    2087             :  * If lockheld is true, the caller is already holding the partition lock
    2088             :  * of the partition containing the scratch entry.
    2089             :  */
    2090             : static void
    2091         246 : RemoveScratchTarget(bool lockheld)
    2092             : {
    2093             :     bool        found;
    2094             : 
    2095             :     Assert(LWLockHeldByMe(SerializablePredicateListLock));
    2096             : 
    2097         246 :     if (!lockheld)
    2098           0 :         LWLockAcquire(ScratchPartitionLock, LW_EXCLUSIVE);
    2099         246 :     hash_search_with_hash_value(PredicateLockTargetHash,
    2100             :                                 &ScratchTargetTag,
    2101             :                                 ScratchTargetTagHash,
    2102             :                                 HASH_REMOVE, &found);
    2103             :     Assert(found);
    2104         246 :     if (!lockheld)
    2105           0 :         LWLockRelease(ScratchPartitionLock);
    2106         246 : }
    2107             : 
    2108             : /*
    2109             :  * Re-insert the dummy entry in predicate lock target hash.
    2110             :  */
    2111             : static void
    2112         246 : RestoreScratchTarget(bool lockheld)
    2113             : {
    2114             :     bool        found;
    2115             : 
    2116             :     Assert(LWLockHeldByMe(SerializablePredicateListLock));
    2117             : 
    2118         246 :     if (!lockheld)
    2119           0 :         LWLockAcquire(ScratchPartitionLock, LW_EXCLUSIVE);
    2120         246 :     hash_search_with_hash_value(PredicateLockTargetHash,
    2121             :                                 &ScratchTargetTag,
    2122             :                                 ScratchTargetTagHash,
    2123             :                                 HASH_ENTER, &found);
    2124             :     Assert(!found);
    2125         246 :     if (!lockheld)
    2126           0 :         LWLockRelease(ScratchPartitionLock);
    2127         246 : }
    2128             : 
    2129             : /*
    2130             :  * Check whether the list of related predicate locks is empty for a
    2131             :  * predicate lock target, and remove the target if it is.
    2132             :  */
    2133             : static void
    2134        8408 : RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
    2135             : {
    2136             :     PREDICATELOCKTARGET *rmtarget PG_USED_FOR_ASSERTS_ONLY;
    2137             : 
    2138             :     Assert(LWLockHeldByMe(SerializablePredicateListLock));
    2139             : 
    2140             :     /* Can't remove it until no locks at this target. */
    2141        8408 :     if (!dlist_is_empty(&target->predicateLocks))
    2142        1922 :         return;
    2143             : 
    2144             :     /* Actually remove the target. */
    2145        6486 :     rmtarget = hash_search_with_hash_value(PredicateLockTargetHash,
    2146        6486 :                                            &target->tag,
    2147             :                                            targettaghash,
    2148             :                                            HASH_REMOVE, NULL);
    2149             :     Assert(rmtarget == target);
    2150             : }
    2151             : 
    2152             : /*
    2153             :  * Delete child target locks owned by this process.
    2154             :  * This implementation is assuming that the usage of each target tag field
    2155             :  * is uniform.  No need to make this hard if we don't have to.
    2156             :  *
    2157             :  * We acquire an LWLock in the case of parallel mode, because worker
    2158             :  * backends have access to the leader's SERIALIZABLEXACT.  Otherwise,
    2159             :  * we aren't acquiring LWLocks for the predicate lock or lock
    2160             :  * target structures associated with this transaction unless we're going
    2161             :  * to modify them, because no other process is permitted to modify our
    2162             :  * locks.
    2163             :  */
    2164             : static void
    2165        4688 : DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
    2166             : {
    2167             :     SERIALIZABLEXACT *sxact;
    2168             :     PREDICATELOCK *predlock;
    2169             :     dlist_mutable_iter iter;
    2170             : 
    2171        4688 :     LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
    2172        4688 :     sxact = MySerializableXact;
    2173        4688 :     if (IsInParallelMode())
    2174          22 :         LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
    2175             : 
    2176       15532 :     dlist_foreach_modify(iter, &sxact->predicateLocks)
    2177             :     {
    2178             :         PREDICATELOCKTAG oldlocktag;
    2179             :         PREDICATELOCKTARGET *oldtarget;
    2180             :         PREDICATELOCKTARGETTAG oldtargettag;
    2181             : 
    2182       10844 :         predlock = dlist_container(PREDICATELOCK, xactLink, iter.cur);
    2183             : 
    2184       10844 :         oldlocktag = predlock->tag;
    2185             :         Assert(oldlocktag.myXact == sxact);
    2186       10844 :         oldtarget = oldlocktag.myTarget;
    2187       10844 :         oldtargettag = oldtarget->tag;
    2188             : 
    2189       10844 :         if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
    2190             :         {
    2191             :             uint32      oldtargettaghash;
    2192             :             LWLock     *partitionLock;
    2193             :             PREDICATELOCK *rmpredlock PG_USED_FOR_ASSERTS_ONLY;
    2194             : 
    2195        1998 :             oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
    2196        1998 :             partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
    2197             : 
    2198        1998 :             LWLockAcquire(partitionLock, LW_EXCLUSIVE);
    2199             : 
    2200        1998 :             dlist_delete(&predlock->xactLink);
    2201        1998 :             dlist_delete(&predlock->targetLink);
    2202        1998 :             rmpredlock = hash_search_with_hash_value
    2203             :                 (PredicateLockHash,
    2204             :                  &oldlocktag,
    2205        1998 :                  PredicateLockHashCodeFromTargetHashCode(&oldlocktag,
    2206             :                                                          oldtargettaghash),
    2207             :                  HASH_REMOVE, NULL);
    2208             :             Assert(rmpredlock == predlock);
    2209             : 
    2210        1998 :             RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
    2211             : 
    2212        1998 :             LWLockRelease(partitionLock);
    2213             : 
    2214        1998 :             DecrementParentLocks(&oldtargettag);
    2215             :         }
    2216             :     }
    2217        4688 :     if (IsInParallelMode())
    2218          22 :         LWLockRelease(&sxact->perXactPredicateListLock);
    2219        4688 :     LWLockRelease(SerializablePredicateListLock);
    2220        4688 : }
    2221             : 
    2222             : /*
    2223             :  * Returns the promotion limit for a given predicate lock target.  This is the
    2224             :  * max number of descendant locks allowed before promoting to the specified
    2225             :  * tag. Note that the limit includes non-direct descendants (e.g., both tuples
    2226             :  * and pages for a relation lock).
    2227             :  *
    2228             :  * Currently the default limit is 2 for a page lock, and half of the value of
    2229             :  * max_pred_locks_per_transaction - 1 for a relation lock, to match behavior
    2230             :  * of earlier releases when upgrading.
    2231             :  *
    2232             :  * TODO SSI: We should probably add additional GUCs to allow a maximum ratio
    2233             :  * of page and tuple locks based on the pages in a relation, and the maximum
    2234             :  * ratio of tuple locks to tuples in a page.  This would provide more
    2235             :  * generally "balanced" allocation of locks to where they are most useful,
    2236             :  * while still allowing the absolute numbers to prevent one relation from
    2237             :  * tying up all predicate lock resources.
    2238             :  */
    2239             : static int
    2240       10768 : MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag)
    2241             : {
    2242       10768 :     switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
    2243             :     {
    2244        7036 :         case PREDLOCKTAG_RELATION:
    2245        7036 :             return max_predicate_locks_per_relation < 0
    2246             :                 ? (max_predicate_locks_per_xact
    2247        7036 :                    / (-max_predicate_locks_per_relation)) - 1
    2248        7036 :                 : max_predicate_locks_per_relation;
    2249             : 
    2250        3732 :         case PREDLOCKTAG_PAGE:
    2251        3732 :             return max_predicate_locks_per_page;
    2252             : 
    2253           0 :         case PREDLOCKTAG_TUPLE:
    2254             : 
    2255             :             /*
    2256             :              * not reachable: nothing is finer-granularity than a tuple, so we
    2257             :              * should never try to promote to it.
    2258             :              */
    2259             :             Assert(false);
    2260           0 :             return 0;
    2261             :     }
    2262             : 
    2263             :     /* not reachable */
    2264             :     Assert(false);
    2265           0 :     return 0;
    2266             : }
    2267             : 
    2268             : /*
    2269             :  * For all ancestors of a newly-acquired predicate lock, increment
    2270             :  * their child count in the parent hash table. If any of them have
    2271             :  * more descendants than their promotion threshold, acquire the
    2272             :  * coarsest such lock.
    2273             :  *
    2274             :  * Returns true if a parent lock was acquired and false otherwise.
    2275             :  */
    2276             : static bool
    2277        8420 : CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag)
    2278             : {
    2279             :     PREDICATELOCKTARGETTAG targettag,
    2280             :                 nexttag,
    2281             :                 promotiontag;
    2282             :     LOCALPREDICATELOCK *parentlock;
    2283             :     bool        found,
    2284             :                 promote;
    2285             : 
    2286        8420 :     promote = false;
    2287             : 
    2288        8420 :     targettag = *reqtag;
    2289             : 
    2290             :     /* check parents iteratively */
    2291       19188 :     while (GetParentPredicateLockTag(&targettag, &nexttag))
    2292             :     {
    2293       10768 :         targettag = nexttag;
    2294       10768 :         parentlock = (LOCALPREDICATELOCK *) hash_search(LocalPredicateLockHash,
    2295             :                                                         &targettag,
    2296             :                                                         HASH_ENTER,
    2297             :                                                         &found);
    2298       10768 :         if (!found)
    2299             :         {
    2300        6646 :             parentlock->held = false;
    2301        6646 :             parentlock->childLocks = 1;
    2302             :         }
    2303             :         else
    2304        4122 :             parentlock->childLocks++;
    2305             : 
    2306       10768 :         if (parentlock->childLocks >
    2307       10768 :             MaxPredicateChildLocks(&targettag))
    2308             :         {
    2309             :             /*
    2310             :              * We should promote to this parent lock. Continue to check its
    2311             :              * ancestors, however, both to get their child counts right and to
    2312             :              * check whether we should just go ahead and promote to one of
    2313             :              * them.
    2314             :              */
    2315         666 :             promotiontag = targettag;
    2316         666 :             promote = true;
    2317             :         }
    2318             :     }
    2319             : 
    2320        8420 :     if (promote)
    2321             :     {
    2322             :         /* acquire coarsest ancestor eligible for promotion */
    2323         666 :         PredicateLockAcquire(&promotiontag);
    2324         666 :         return true;
    2325             :     }
    2326             :     else
    2327        7754 :         return false;
    2328             : }
    2329             : 
    2330             : /*
    2331             :  * When releasing a lock, decrement the child count on all ancestor
    2332             :  * locks.
    2333             :  *
    2334             :  * This is called only when releasing a lock via
    2335             :  * DeleteChildTargetLocks (i.e. when a lock becomes redundant because
    2336             :  * we've acquired its parent, possibly due to promotion) or when a new
    2337             :  * MVCC write lock makes the predicate lock unnecessary. There's no
    2338             :  * point in calling it when locks are released at transaction end, as
    2339             :  * this information is no longer needed.
    2340             :  */
    2341             : static void
    2342        2760 : DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
    2343             : {
    2344             :     PREDICATELOCKTARGETTAG parenttag,
    2345             :                 nexttag;
    2346             : 
    2347        2760 :     parenttag = *targettag;
    2348             : 
    2349        8280 :     while (GetParentPredicateLockTag(&parenttag, &nexttag))
    2350             :     {
    2351             :         uint32      targettaghash;
    2352             :         LOCALPREDICATELOCK *parentlock,
    2353             :                    *rmlock PG_USED_FOR_ASSERTS_ONLY;
    2354             : 
    2355        5520 :         parenttag = nexttag;
    2356        5520 :         targettaghash = PredicateLockTargetTagHashCode(&parenttag);
    2357             :         parentlock = (LOCALPREDICATELOCK *)
    2358        5520 :             hash_search_with_hash_value(LocalPredicateLockHash,
    2359             :                                         &parenttag, targettaghash,
    2360             :                                         HASH_FIND, NULL);
    2361             : 
    2362             :         /*
    2363             :          * There's a small chance the parent lock doesn't exist in the lock
    2364             :          * table. This can happen if we prematurely removed it because an
    2365             :          * index split caused the child refcount to be off.
    2366             :          */
    2367        5520 :         if (parentlock == NULL)
    2368           0 :             continue;
    2369             : 
    2370        5520 :         parentlock->childLocks--;
    2371             : 
    2372             :         /*
    2373             :          * Under similar circumstances the parent lock's refcount might be
    2374             :          * zero. This only happens if we're holding that lock (otherwise we
    2375             :          * would have removed the entry).
    2376             :          */
    2377        5520 :         if (parentlock->childLocks < 0)
    2378             :         {
    2379             :             Assert(parentlock->held);
    2380           0 :             parentlock->childLocks = 0;
    2381             :         }
    2382             : 
    2383        5520 :         if ((parentlock->childLocks == 0) && (!parentlock->held))
    2384             :         {
    2385             :             rmlock = (LOCALPREDICATELOCK *)
    2386        1500 :                 hash_search_with_hash_value(LocalPredicateLockHash,
    2387             :                                             &parenttag, targettaghash,
    2388             :                                             HASH_REMOVE, NULL);
    2389             :             Assert(rmlock == parentlock);
    2390             :         }
    2391             :     }
    2392        2760 : }
    2393             : 
    2394             : /*
    2395             :  * Indicate that a predicate lock on the given target is held by the
    2396             :  * specified transaction. Has no effect if the lock is already held.
    2397             :  *
    2398             :  * This updates the lock table and the sxact's lock list, and creates
    2399             :  * the lock target if necessary, but does *not* do anything related to
    2400             :  * granularity promotion or the local lock table. See
    2401             :  * PredicateLockAcquire for that.
    2402             :  */
    2403             : static void
    2404        8420 : CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag,
    2405             :                     uint32 targettaghash,
    2406             :                     SERIALIZABLEXACT *sxact)
    2407             : {
    2408             :     PREDICATELOCKTARGET *target;
    2409             :     PREDICATELOCKTAG locktag;
    2410             :     PREDICATELOCK *lock;
    2411             :     LWLock     *partitionLock;
    2412             :     bool        found;
    2413             : 
    2414        8420 :     partitionLock = PredicateLockHashPartitionLock(targettaghash);
    2415             : 
    2416        8420 :     LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
    2417        8420 :     if (IsInParallelMode())
    2418          32 :         LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
    2419        8420 :     LWLockAcquire(partitionLock, LW_EXCLUSIVE);
    2420             : 
    2421             :     /* Make sure that the target is represented. */
    2422             :     target = (PREDICATELOCKTARGET *)
    2423        8420 :         hash_search_with_hash_value(PredicateLockTargetHash,
    2424             :                                     targettag, targettaghash,
    2425             :                                     HASH_ENTER_NULL, &found);
    2426        8420 :     if (!target)
    2427           0 :         ereport(ERROR,
    2428             :                 (errcode(ERRCODE_OUT_OF_MEMORY),
    2429             :                  errmsg("out of shared memory"),
    2430             :                  errhint("You might need to increase %s.", "max_pred_locks_per_transaction")));
    2431        8420 :     if (!found)
    2432        6486 :         dlist_init(&target->predicateLocks);
    2433             : 
    2434             :     /* We've got the sxact and target, make sure they're joined. */
    2435        8420 :     locktag.myTarget = target;
    2436        8420 :     locktag.myXact = sxact;
    2437             :     lock = (PREDICATELOCK *)
    2438        8420 :         hash_search_with_hash_value(PredicateLockHash, &locktag,
    2439        8420 :                                     PredicateLockHashCodeFromTargetHashCode(&locktag, targettaghash),
    2440             :                                     HASH_ENTER_NULL, &found);
    2441        8420 :     if (!lock)
    2442           0 :         ereport(ERROR,
    2443             :                 (errcode(ERRCODE_OUT_OF_MEMORY),
    2444             :                  errmsg("out of shared memory"),
    2445             :                  errhint("You might need to increase %s.", "max_pred_locks_per_transaction")));
    2446             : 
    2447        8420 :     if (!found)
    2448             :     {
    2449        8408 :         dlist_push_tail(&target->predicateLocks, &lock->targetLink);
    2450        8408 :         dlist_push_tail(&sxact->predicateLocks, &lock->xactLink);
    2451        8408 :         lock->commitSeqNo = InvalidSerCommitSeqNo;
    2452             :     }
    2453             : 
    2454        8420 :     LWLockRelease(partitionLock);
    2455        8420 :     if (IsInParallelMode())
    2456          32 :         LWLockRelease(&sxact->perXactPredicateListLock);
    2457        8420 :     LWLockRelease(SerializablePredicateListLock);
    2458        8420 : }
    2459             : 
    2460             : /*
    2461             :  * Acquire a predicate lock on the specified target for the current
    2462             :  * connection if not already held. This updates the local lock table
    2463             :  * and uses it to implement granularity promotion. It will consolidate
    2464             :  * multiple locks into a coarser lock if warranted, and will release
    2465             :  * any finer-grained locks covered by the new one.
    2466             :  */
    2467             : static void
    2468       52470 : PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
    2469             : {
    2470             :     uint32      targettaghash;
    2471             :     bool        found;
    2472             :     LOCALPREDICATELOCK *locallock;
    2473             : 
    2474             :     /* Do we have the lock already, or a covering lock? */
    2475       52470 :     if (PredicateLockExists(targettag))
    2476       44050 :         return;
    2477             : 
    2478       52062 :     if (CoarserLockCovers(targettag))
    2479       43642 :         return;
    2480             : 
    2481             :     /* the same hash and LW lock apply to the lock target and the local lock. */
    2482        8420 :     targettaghash = PredicateLockTargetTagHashCode(targettag);
    2483             : 
    2484             :     /* Acquire lock in local table */
    2485             :     locallock = (LOCALPREDICATELOCK *)
    2486        8420 :         hash_search_with_hash_value(LocalPredicateLockHash,
    2487             :                                     targettag, targettaghash,
    2488             :                                     HASH_ENTER, &found);
    2489        8420 :     locallock->held = true;
    2490        8420 :     if (!found)
    2491        7754 :         locallock->childLocks = 0;
    2492             : 
    2493             :     /* Actually create the lock */
    2494        8420 :     CreatePredicateLock(targettag, targettaghash, MySerializableXact);
    2495             : 
    2496             :     /*
    2497             :      * Lock has been acquired. Check whether it should be promoted to a
    2498             :      * coarser granularity, or whether there are finer-granularity locks to
    2499             :      * clean up.
    2500             :      */
    2501        8420 :     if (CheckAndPromotePredicateLockRequest(targettag))
    2502             :     {
    2503             :         /*
    2504             :          * Lock request was promoted to a coarser-granularity lock, and that
    2505             :          * lock was acquired. It will delete this lock and any of its
    2506             :          * children, so we're done.
    2507             :          */
    2508             :     }
    2509             :     else
    2510             :     {
    2511             :         /* Clean up any finer-granularity locks */
    2512        7754 :         if (GET_PREDICATELOCKTARGETTAG_TYPE(*targettag) != PREDLOCKTAG_TUPLE)
    2513        4688 :             DeleteChildTargetLocks(targettag);
    2514             :     }
    2515             : }
    2516             : 
    2517             : 
    2518             : /*
    2519             :  *      PredicateLockRelation
    2520             :  *
    2521             :  * Gets a predicate lock at the relation level.
    2522             :  * Skip if not in full serializable transaction isolation level.
    2523             :  * Skip if this is a temporary table.
    2524             :  * Clear any finer-grained predicate locks this session has on the relation.
    2525             :  */
    2526             : void
    2527      528196 : PredicateLockRelation(Relation relation, Snapshot snapshot)
    2528             : {
    2529             :     PREDICATELOCKTARGETTAG tag;
    2530             : 
    2531      528196 :     if (!SerializationNeededForRead(relation, snapshot))
    2532      526770 :         return;
    2533             : 
    2534        1426 :     SET_PREDICATELOCKTARGETTAG_RELATION(tag,
    2535             :                                         relation->rd_locator.dbOid,
    2536             :                                         relation->rd_id);
    2537        1426 :     PredicateLockAcquire(&tag);
    2538             : }
    2539             : 
    2540             : /*
    2541             :  *      PredicateLockPage
    2542             :  *
    2543             :  * Gets a predicate lock at the page level.
    2544             :  * Skip if not in full serializable transaction isolation level.
    2545             :  * Skip if this is a temporary table.
    2546             :  * Skip if a coarser predicate lock already covers this page.
    2547             :  * Clear any finer-grained predicate locks this session has on the relation.
    2548             :  */
    2549             : void
    2550    13147978 : PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
    2551             : {
    2552             :     PREDICATELOCKTARGETTAG tag;
    2553             : 
    2554    13147978 :     if (!SerializationNeededForRead(relation, snapshot))
    2555    13145108 :         return;
    2556             : 
    2557        2870 :     SET_PREDICATELOCKTARGETTAG_PAGE(tag,
    2558             :                                     relation->rd_locator.dbOid,
    2559             :                                     relation->rd_id,
    2560             :                                     blkno);
    2561        2870 :     PredicateLockAcquire(&tag);
    2562             : }
    2563             : 
    2564             : /*
    2565             :  *      PredicateLockTID
    2566             :  *
    2567             :  * Gets a predicate lock at the tuple level.
    2568             :  * Skip if not in full serializable transaction isolation level.
    2569             :  * Skip if this is a temporary table.
    2570             :  */
    2571             : void
    2572    23983350 : PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot,
    2573             :                  TransactionId tuple_xid)
    2574             : {
    2575             :     PREDICATELOCKTARGETTAG tag;
    2576             : 
    2577    23983350 :     if (!SerializationNeededForRead(relation, snapshot))
    2578    23935842 :         return;
    2579             : 
    2580             :     /*
    2581             :      * Return if this xact wrote it.
    2582             :      */
    2583       47508 :     if (relation->rd_index == NULL)
    2584             :     {
    2585             :         /* If we wrote it; we already have a write lock. */
    2586       47508 :         if (TransactionIdIsCurrentTransactionId(tuple_xid))
    2587           0 :             return;
    2588             :     }
    2589             : 
    2590             :     /*
    2591             :      * Do quick-but-not-definitive test for a relation lock first.  This will
    2592             :      * never cause a return when the relation is *not* locked, but will
    2593             :      * occasionally let the check continue when there really *is* a relation
    2594             :      * level lock.
    2595             :      */
    2596       47508 :     SET_PREDICATELOCKTARGETTAG_RELATION(tag,
    2597             :                                         relation->rd_locator.dbOid,
    2598             :                                         relation->rd_id);
    2599       47508 :     if (PredicateLockExists(&tag))
    2600           0 :         return;
    2601             : 
    2602       47508 :     SET_PREDICATELOCKTARGETTAG_TUPLE(tag,
    2603             :                                      relation->rd_locator.dbOid,
    2604             :                                      relation->rd_id,
    2605             :                                      ItemPointerGetBlockNumber(tid),
    2606             :                                      ItemPointerGetOffsetNumber(tid));
    2607       47508 :     PredicateLockAcquire(&tag);
    2608             : }
    2609             : 
    2610             : 
    2611             : /*
    2612             :  *      DeleteLockTarget
    2613             :  *
    2614             :  * Remove a predicate lock target along with any locks held for it.
    2615             :  *
    2616             :  * Caller must hold SerializablePredicateListLock and the
    2617             :  * appropriate hash partition lock for the target.
    2618             :  */
    2619             : static void
    2620           0 : DeleteLockTarget(PREDICATELOCKTARGET *target, uint32 targettaghash)
    2621             : {
    2622             :     dlist_mutable_iter iter;
    2623             : 
    2624             :     Assert(LWLockHeldByMeInMode(SerializablePredicateListLock,
    2625             :                                 LW_EXCLUSIVE));
    2626             :     Assert(LWLockHeldByMe(PredicateLockHashPartitionLock(targettaghash)));
    2627             : 
    2628           0 :     LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    2629             : 
    2630           0 :     dlist_foreach_modify(iter, &target->predicateLocks)
    2631             :     {
    2632           0 :         PREDICATELOCK *predlock =
    2633           0 :             dlist_container(PREDICATELOCK, targetLink, iter.cur);
    2634             :         bool        found;
    2635             : 
    2636           0 :         dlist_delete(&(predlock->xactLink));
    2637           0 :         dlist_delete(&(predlock->targetLink));
    2638             : 
    2639           0 :         hash_search_with_hash_value
    2640             :             (PredicateLockHash,
    2641           0 :              &predlock->tag,
    2642           0 :              PredicateLockHashCodeFromTargetHashCode(&predlock->tag,
    2643             :                                                      targettaghash),
    2644             :              HASH_REMOVE, &found);
    2645             :         Assert(found);
    2646             :     }
    2647           0 :     LWLockRelease(SerializableXactHashLock);
    2648             : 
    2649             :     /* Remove the target itself, if possible. */
    2650           0 :     RemoveTargetIfNoLongerUsed(target, targettaghash);
    2651           0 : }
    2652             : 
    2653             : 
    2654             : /*
    2655             :  *      TransferPredicateLocksToNewTarget
    2656             :  *
    2657             :  * Move or copy all the predicate locks for a lock target, for use by
    2658             :  * index page splits/combines and other things that create or replace
    2659             :  * lock targets. If 'removeOld' is true, the old locks and the target
    2660             :  * will be removed.
    2661             :  *
    2662             :  * Returns true on success, or false if we ran out of shared memory to
    2663             :  * allocate the new target or locks. Guaranteed to always succeed if
    2664             :  * removeOld is set (by using the scratch entry in PredicateLockTargetHash
    2665             :  * for scratch space).
    2666             :  *
    2667             :  * Warning: the "removeOld" option should be used only with care,
    2668             :  * because this function does not (indeed, can not) update other
    2669             :  * backends' LocalPredicateLockHash. If we are only adding new
    2670             :  * entries, this is not a problem: the local lock table is used only
    2671             :  * as a hint, so missing entries for locks that are held are
    2672             :  * OK. Having entries for locks that are no longer held, as can happen
    2673             :  * when using "removeOld", is not in general OK. We can only use it
    2674             :  * safely when replacing a lock with a coarser-granularity lock that
    2675             :  * covers it, or if we are absolutely certain that no one will need to
    2676             :  * refer to that lock in the future.
    2677             :  *
    2678             :  * Caller must hold SerializablePredicateListLock exclusively.
    2679             :  */
    2680             : static bool
    2681         108 : TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag,
    2682             :                                   PREDICATELOCKTARGETTAG newtargettag,
    2683             :                                   bool removeOld)
    2684             : {
    2685             :     uint32      oldtargettaghash;
    2686             :     LWLock     *oldpartitionLock;
    2687             :     PREDICATELOCKTARGET *oldtarget;
    2688             :     uint32      newtargettaghash;
    2689             :     LWLock     *newpartitionLock;
    2690             :     bool        found;
    2691         108 :     bool        outOfShmem = false;
    2692             : 
    2693             :     Assert(LWLockHeldByMeInMode(SerializablePredicateListLock,
    2694             :                                 LW_EXCLUSIVE));
    2695             : 
    2696         108 :     oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
    2697         108 :     newtargettaghash = PredicateLockTargetTagHashCode(&newtargettag);
    2698         108 :     oldpartitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
    2699         108 :     newpartitionLock = PredicateLockHashPartitionLock(newtargettaghash);
    2700             : 
    2701         108 :     if (removeOld)
    2702             :     {
    2703             :         /*
    2704             :          * Remove the dummy entry to give us scratch space, so we know we'll
    2705             :          * be able to create the new lock target.
    2706             :          */
    2707           0 :         RemoveScratchTarget(false);
    2708             :     }
    2709             : 
    2710             :     /*
    2711             :      * We must get the partition locks in ascending sequence to avoid
    2712             :      * deadlocks. If old and new partitions are the same, we must request the
    2713             :      * lock only once.
    2714             :      */
    2715         108 :     if (oldpartitionLock < newpartitionLock)
    2716             :     {
    2717          48 :         LWLockAcquire(oldpartitionLock,
    2718          48 :                       (removeOld ? LW_EXCLUSIVE : LW_SHARED));
    2719          48 :         LWLockAcquire(newpartitionLock, LW_EXCLUSIVE);
    2720             :     }
    2721          60 :     else if (oldpartitionLock > newpartitionLock)
    2722             :     {
    2723          56 :         LWLockAcquire(newpartitionLock, LW_EXCLUSIVE);
    2724          56 :         LWLockAcquire(oldpartitionLock,
    2725          56 :                       (removeOld ? LW_EXCLUSIVE : LW_SHARED));
    2726             :     }
    2727             :     else
    2728           4 :         LWLockAcquire(newpartitionLock, LW_EXCLUSIVE);
    2729             : 
    2730             :     /*
    2731             :      * Look for the old target.  If not found, that's OK; no predicate locks
    2732             :      * are affected, so we can just clean up and return. If it does exist,
    2733             :      * walk its list of predicate locks and move or copy them to the new
    2734             :      * target.
    2735             :      */
    2736         108 :     oldtarget = hash_search_with_hash_value(PredicateLockTargetHash,
    2737             :                                             &oldtargettag,
    2738             :                                             oldtargettaghash,
    2739             :                                             HASH_FIND, NULL);
    2740             : 
    2741         108 :     if (oldtarget)
    2742             :     {
    2743             :         PREDICATELOCKTARGET *newtarget;
    2744             :         PREDICATELOCKTAG newpredlocktag;
    2745             :         dlist_mutable_iter iter;
    2746             : 
    2747           0 :         newtarget = hash_search_with_hash_value(PredicateLockTargetHash,
    2748             :                                                 &newtargettag,
    2749             :                                                 newtargettaghash,
    2750             :                                                 HASH_ENTER_NULL, &found);
    2751             : 
    2752           0 :         if (!newtarget)
    2753             :         {
    2754             :             /* Failed to allocate due to insufficient shmem */
    2755           0 :             outOfShmem = true;
    2756           0 :             goto exit;
    2757             :         }
    2758             : 
    2759             :         /* If we created a new entry, initialize it */
    2760           0 :         if (!found)
    2761           0 :             dlist_init(&newtarget->predicateLocks);
    2762             : 
    2763           0 :         newpredlocktag.myTarget = newtarget;
    2764             : 
    2765             :         /*
    2766             :          * Loop through all the locks on the old target, replacing them with
    2767             :          * locks on the new target.
    2768             :          */
    2769           0 :         LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    2770             : 
    2771           0 :         dlist_foreach_modify(iter, &oldtarget->predicateLocks)
    2772             :         {
    2773           0 :             PREDICATELOCK *oldpredlock =
    2774           0 :                 dlist_container(PREDICATELOCK, targetLink, iter.cur);
    2775             :             PREDICATELOCK *newpredlock;
    2776           0 :             SerCommitSeqNo oldCommitSeqNo = oldpredlock->commitSeqNo;
    2777             : 
    2778           0 :             newpredlocktag.myXact = oldpredlock->tag.myXact;
    2779             : 
    2780           0 :             if (removeOld)
    2781             :             {
    2782           0 :                 dlist_delete(&(oldpredlock->xactLink));
    2783           0 :                 dlist_delete(&(oldpredlock->targetLink));
    2784             : 
    2785           0 :                 hash_search_with_hash_value
    2786             :                     (PredicateLockHash,
    2787           0 :                      &oldpredlock->tag,
    2788           0 :                      PredicateLockHashCodeFromTargetHashCode(&oldpredlock->tag,
    2789             :                                                              oldtargettaghash),
    2790             :                      HASH_REMOVE, &found);
    2791             :                 Assert(found);
    2792             :             }
    2793             : 
    2794             :             newpredlock = (PREDICATELOCK *)
    2795           0 :                 hash_search_with_hash_value(PredicateLockHash,
    2796             :                                             &newpredlocktag,
    2797           0 :                                             PredicateLockHashCodeFromTargetHashCode(&newpredlocktag,
    2798             :                                                                                     newtargettaghash),
    2799             :                                             HASH_ENTER_NULL,
    2800             :                                             &found);
    2801           0 :             if (!newpredlock)
    2802             :             {
    2803             :                 /* Out of shared memory. Undo what we've done so far. */
    2804           0 :                 LWLockRelease(SerializableXactHashLock);
    2805           0 :                 DeleteLockTarget(newtarget, newtargettaghash);
    2806           0 :                 outOfShmem = true;
    2807           0 :                 goto exit;
    2808             :             }
    2809           0 :             if (!found)
    2810             :             {
    2811           0 :                 dlist_push_tail(&(newtarget->predicateLocks),
    2812             :                                 &(newpredlock->targetLink));
    2813           0 :                 dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
    2814             :                                 &(newpredlock->xactLink));
    2815           0 :                 newpredlock->commitSeqNo = oldCommitSeqNo;
    2816             :             }
    2817             :             else
    2818             :             {
    2819           0 :                 if (newpredlock->commitSeqNo < oldCommitSeqNo)
    2820           0 :                     newpredlock->commitSeqNo = oldCommitSeqNo;
    2821             :             }
    2822             : 
    2823             :             Assert(newpredlock->commitSeqNo != 0);
    2824             :             Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
    2825             :                    || (newpredlock->tag.myXact == OldCommittedSxact));
    2826             :         }
    2827           0 :         LWLockRelease(SerializableXactHashLock);
    2828             : 
    2829           0 :         if (removeOld)
    2830             :         {
    2831             :             Assert(dlist_is_empty(&oldtarget->predicateLocks));
    2832           0 :             RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
    2833             :         }
    2834             :     }
    2835             : 
    2836             : 
    2837         108 : exit:
    2838             :     /* Release partition locks in reverse order of acquisition. */
    2839         108 :     if (oldpartitionLock < newpartitionLock)
    2840             :     {
    2841          48 :         LWLockRelease(newpartitionLock);
    2842          48 :         LWLockRelease(oldpartitionLock);
    2843             :     }
    2844          60 :     else if (oldpartitionLock > newpartitionLock)
    2845             :     {
    2846          56 :         LWLockRelease(oldpartitionLock);
    2847          56 :         LWLockRelease(newpartitionLock);
    2848             :     }
    2849             :     else
    2850           4 :         LWLockRelease(newpartitionLock);
    2851             : 
    2852         108 :     if (removeOld)
    2853             :     {
    2854             :         /* We shouldn't run out of memory if we're moving locks */
    2855             :         Assert(!outOfShmem);
    2856             : 
    2857             :         /* Put the scratch entry back */
    2858           0 :         RestoreScratchTarget(false);
    2859             :     }
    2860             : 
    2861         108 :     return !outOfShmem;
    2862             : }
    2863             : 
    2864             : /*
    2865             :  * Drop all predicate locks of any granularity from the specified relation,
    2866             :  * which can be a heap relation or an index relation.  If 'transfer' is true,
    2867             :  * acquire a relation lock on the heap for any transactions with any lock(s)
    2868             :  * on the specified relation.
    2869             :  *
    2870             :  * This requires grabbing a lot of LW locks and scanning the entire lock
    2871             :  * target table for matches.  That makes this more expensive than most
    2872             :  * predicate lock management functions, but it will only be called for DDL
    2873             :  * type commands that are expensive anyway, and there are fast returns when
    2874             :  * no serializable transactions are active or the relation is temporary.
    2875             :  *
    2876             :  * We don't use the TransferPredicateLocksToNewTarget function because it
    2877             :  * acquires its own locks on the partitions of the two targets involved,
    2878             :  * and we'll already be holding all partition locks.
    2879             :  *
    2880             :  * We can't throw an error from here, because the call could be from a
    2881             :  * transaction which is not serializable.
    2882             :  *
    2883             :  * NOTE: This is currently only called with transfer set to true, but that may
    2884             :  * change.  If we decide to clean up the locks from a table on commit of a
    2885             :  * transaction which executed DROP TABLE, the false condition will be useful.
    2886             :  */
    2887             : static void
    2888       27486 : DropAllPredicateLocksFromTable(Relation relation, bool transfer)
    2889             : {
    2890             :     HASH_SEQ_STATUS seqstat;
    2891             :     PREDICATELOCKTARGET *oldtarget;
    2892             :     PREDICATELOCKTARGET *heaptarget;
    2893             :     Oid         dbId;
    2894             :     Oid         relId;
    2895             :     Oid         heapId;
    2896             :     int         i;
    2897             :     bool        isIndex;
    2898             :     bool        found;
    2899             :     uint32      heaptargettaghash;
    2900             : 
    2901             :     /*
    2902             :      * Bail out quickly if there are no serializable transactions running.
    2903             :      * It's safe to check this without taking locks because the caller is
    2904             :      * holding an ACCESS EXCLUSIVE lock on the relation.  No new locks which
    2905             :      * would matter here can be acquired while that is held.
    2906             :      */
    2907       27486 :     if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
    2908       27240 :         return;
    2909             : 
    2910         354 :     if (!PredicateLockingNeededForRelation(relation))
    2911         108 :         return;
    2912             : 
    2913         246 :     dbId = relation->rd_locator.dbOid;
    2914         246 :     relId = relation->rd_id;
    2915         246 :     if (relation->rd_index == NULL)
    2916             :     {
    2917           2 :         isIndex = false;
    2918           2 :         heapId = relId;
    2919             :     }
    2920             :     else
    2921             :     {
    2922         244 :         isIndex = true;
    2923         244 :         heapId = relation->rd_index->indrelid;
    2924             :     }
    2925             :     Assert(heapId != InvalidOid);
    2926             :     Assert(transfer || !isIndex);   /* index OID only makes sense with
    2927             :                                      * transfer */
    2928             : 
    2929             :     /* Retrieve first time needed, then keep. */
    2930         246 :     heaptargettaghash = 0;
    2931         246 :     heaptarget = NULL;
    2932             : 
    2933             :     /* Acquire locks on all lock partitions */
    2934         246 :     LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
    2935        4182 :     for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
    2936        3936 :         LWLockAcquire(PredicateLockHashPartitionLockByIndex(i), LW_EXCLUSIVE);
    2937         246 :     LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    2938             : 
    2939             :     /*
    2940             :      * Remove the dummy entry to give us scratch space, so we know we'll be
    2941             :      * able to create the new lock target.
    2942             :      */
    2943         246 :     if (transfer)
    2944         246 :         RemoveScratchTarget(true);
    2945             : 
    2946             :     /* Scan through target map */
    2947         246 :     hash_seq_init(&seqstat, PredicateLockTargetHash);
    2948             : 
    2949         490 :     while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
    2950             :     {
    2951             :         dlist_mutable_iter iter;
    2952             : 
    2953             :         /*
    2954             :          * Check whether this is a target which needs attention.
    2955             :          */
    2956         244 :         if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) != relId)
    2957         244 :             continue;           /* wrong relation id */
    2958           0 :         if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
    2959           0 :             continue;           /* wrong database id */
    2960           0 :         if (transfer && !isIndex
    2961           0 :             && GET_PREDICATELOCKTARGETTAG_TYPE(oldtarget->tag) == PREDLOCKTAG_RELATION)
    2962           0 :             continue;           /* already the right lock */
    2963             : 
    2964             :         /*
    2965             :          * If we made it here, we have work to do.  We make sure the heap
    2966             :          * relation lock exists, then we walk the list of predicate locks for
    2967             :          * the old target we found, moving all locks to the heap relation lock
    2968             :          * -- unless they already hold that.
    2969             :          */
    2970             : 
    2971             :         /*
    2972             :          * First make sure we have the heap relation target.  We only need to
    2973             :          * do this once.
    2974             :          */
    2975           0 :         if (transfer && heaptarget == NULL)
    2976             :         {
    2977             :             PREDICATELOCKTARGETTAG heaptargettag;
    2978             : 
    2979           0 :             SET_PREDICATELOCKTARGETTAG_RELATION(heaptargettag, dbId, heapId);
    2980           0 :             heaptargettaghash = PredicateLockTargetTagHashCode(&heaptargettag);
    2981           0 :             heaptarget = hash_search_with_hash_value(PredicateLockTargetHash,
    2982             :                                                      &heaptargettag,
    2983             :                                                      heaptargettaghash,
    2984             :                                                      HASH_ENTER, &found);
    2985           0 :             if (!found)
    2986           0 :                 dlist_init(&heaptarget->predicateLocks);
    2987             :         }
    2988             : 
    2989             :         /*
    2990             :          * Loop through all the locks on the old target, replacing them with
    2991             :          * locks on the new target.
    2992             :          */
    2993           0 :         dlist_foreach_modify(iter, &oldtarget->predicateLocks)
    2994             :         {
    2995           0 :             PREDICATELOCK *oldpredlock =
    2996           0 :                 dlist_container(PREDICATELOCK, targetLink, iter.cur);
    2997             :             PREDICATELOCK *newpredlock;
    2998             :             SerCommitSeqNo oldCommitSeqNo;
    2999             :             SERIALIZABLEXACT *oldXact;
    3000             : 
    3001             :             /*
    3002             :              * Remove the old lock first. This avoids the chance of running
    3003             :              * out of lock structure entries for the hash table.
    3004             :              */
    3005           0 :             oldCommitSeqNo = oldpredlock->commitSeqNo;
    3006           0 :             oldXact = oldpredlock->tag.myXact;
    3007             : 
    3008           0 :             dlist_delete(&(oldpredlock->xactLink));
    3009             : 
    3010             :             /*
    3011             :              * No need for retail delete from oldtarget list, we're removing
    3012             :              * the whole target anyway.
    3013             :              */
    3014           0 :             hash_search(PredicateLockHash,
    3015           0 :                         &oldpredlock->tag,
    3016             :                         HASH_REMOVE, &found);
    3017             :             Assert(found);
    3018             : 
    3019           0 :             if (transfer)
    3020             :             {
    3021             :                 PREDICATELOCKTAG newpredlocktag;
    3022             : 
    3023           0 :                 newpredlocktag.myTarget = heaptarget;
    3024           0 :                 newpredlocktag.myXact = oldXact;
    3025             :                 newpredlock = (PREDICATELOCK *)
    3026           0 :                     hash_search_with_hash_value(PredicateLockHash,
    3027             :                                                 &newpredlocktag,
    3028           0 :                                                 PredicateLockHashCodeFromTargetHashCode(&newpredlocktag,
    3029             :                                                                                         heaptargettaghash),
    3030             :                                                 HASH_ENTER,
    3031             :                                                 &found);
    3032           0 :                 if (!found)
    3033             :                 {
    3034           0 :                     dlist_push_tail(&(heaptarget->predicateLocks),
    3035             :                                     &(newpredlock->targetLink));
    3036           0 :                     dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
    3037             :                                     &(newpredlock->xactLink));
    3038           0 :                     newpredlock->commitSeqNo = oldCommitSeqNo;
    3039             :                 }
    3040             :                 else
    3041             :                 {
    3042           0 :                     if (newpredlock->commitSeqNo < oldCommitSeqNo)
    3043           0 :                         newpredlock->commitSeqNo = oldCommitSeqNo;
    3044             :                 }
    3045             : 
    3046             :                 Assert(newpredlock->commitSeqNo != 0);
    3047             :                 Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
    3048             :                        || (newpredlock->tag.myXact == OldCommittedSxact));
    3049             :             }
    3050             :         }
    3051             : 
    3052           0 :         hash_search(PredicateLockTargetHash, &oldtarget->tag, HASH_REMOVE,
    3053             :                     &found);
    3054             :         Assert(found);
    3055             :     }
    3056             : 
    3057             :     /* Put the scratch entry back */
    3058         246 :     if (transfer)
    3059         246 :         RestoreScratchTarget(true);
    3060             : 
    3061             :     /* Release locks in reverse order */
    3062         246 :     LWLockRelease(SerializableXactHashLock);
    3063        4182 :     for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
    3064        3936 :         LWLockRelease(PredicateLockHashPartitionLockByIndex(i));
    3065         246 :     LWLockRelease(SerializablePredicateListLock);
    3066             : }
    3067             : 
    3068             : /*
    3069             :  * TransferPredicateLocksToHeapRelation
    3070             :  *      For all transactions, transfer all predicate locks for the given
    3071             :  *      relation to a single relation lock on the heap.
    3072             :  */
    3073             : void
    3074       27486 : TransferPredicateLocksToHeapRelation(Relation relation)
    3075             : {
    3076       27486 :     DropAllPredicateLocksFromTable(relation, true);
    3077       27486 : }
    3078             : 
    3079             : 
    3080             : /*
    3081             :  *      PredicateLockPageSplit
    3082             :  *
    3083             :  * Copies any predicate locks for the old page to the new page.
    3084             :  * Skip if this is a temporary table or toast table.
    3085             :  *
    3086             :  * NOTE: A page split (or overflow) affects all serializable transactions,
    3087             :  * even if it occurs in the context of another transaction isolation level.
    3088             :  *
    3089             :  * NOTE: This currently leaves the local copy of the locks without
    3090             :  * information on the new lock which is in shared memory.  This could cause
    3091             :  * problems if enough page splits occur on locked pages without the processes
    3092             :  * which hold the locks getting in and noticing.
    3093             :  */
    3094             : void
    3095       53856 : PredicateLockPageSplit(Relation relation, BlockNumber oldblkno,
    3096             :                        BlockNumber newblkno)
    3097             : {
    3098             :     PREDICATELOCKTARGETTAG oldtargettag;
    3099             :     PREDICATELOCKTARGETTAG newtargettag;
    3100             :     bool        success;
    3101             : 
    3102             :     /*
    3103             :      * Bail out quickly if there are no serializable transactions running.
    3104             :      *
    3105             :      * It's safe to do this check without taking any additional locks. Even if
    3106             :      * a serializable transaction starts concurrently, we know it can't take
    3107             :      * any SIREAD locks on the page being split because the caller is holding
    3108             :      * the associated buffer page lock. Memory reordering isn't an issue; the
    3109             :      * memory barrier in the LWLock acquisition guarantees that this read
    3110             :      * occurs while the buffer page lock is held.
    3111             :      */
    3112       53856 :     if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
    3113       53748 :         return;
    3114             : 
    3115         148 :     if (!PredicateLockingNeededForRelation(relation))
    3116          40 :         return;
    3117             : 
    3118             :     Assert(oldblkno != newblkno);
    3119             :     Assert(BlockNumberIsValid(oldblkno));
    3120             :     Assert(BlockNumberIsValid(newblkno));
    3121             : 
    3122         108 :     SET_PREDICATELOCKTARGETTAG_PAGE(oldtargettag,
    3123             :                                     relation->rd_locator.dbOid,
    3124             :                                     relation->rd_id,
    3125             :                                     oldblkno);
    3126         108 :     SET_PREDICATELOCKTARGETTAG_PAGE(newtargettag,
    3127             :                                     relation->rd_locator.dbOid,
    3128             :                                     relation->rd_id,
    3129             :                                     newblkno);
    3130             : 
    3131         108 :     LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
    3132             : 
    3133             :     /*
    3134             :      * Try copying the locks over to the new page's tag, creating it if
    3135             :      * necessary.
    3136             :      */
    3137         108 :     success = TransferPredicateLocksToNewTarget(oldtargettag,
    3138             :                                                 newtargettag,
    3139             :                                                 false);
    3140             : 
    3141         108 :     if (!success)
    3142             :     {
    3143             :         /*
    3144             :          * No more predicate lock entries are available. Failure isn't an
    3145             :          * option here, so promote the page lock to a relation lock.
    3146             :          */
    3147             : 
    3148             :         /* Get the parent relation lock's lock tag */
    3149           0 :         success = GetParentPredicateLockTag(&oldtargettag,
    3150             :                                             &newtargettag);
    3151             :         Assert(success);
    3152             : 
    3153             :         /*
    3154             :          * Move the locks to the parent. This shouldn't fail.
    3155             :          *
    3156             :          * Note that here we are removing locks held by other backends,
    3157             :          * leading to a possible inconsistency in their local lock hash table.
    3158             :          * This is OK because we're replacing it with a lock that covers the
    3159             :          * old one.
    3160             :          */
    3161           0 :         success = TransferPredicateLocksToNewTarget(oldtargettag,
    3162             :                                                     newtargettag,
    3163             :                                                     true);
    3164             :         Assert(success);
    3165             :     }
    3166             : 
    3167         108 :     LWLockRelease(SerializablePredicateListLock);
    3168             : }
    3169             : 
    3170             : /*
    3171             :  *      PredicateLockPageCombine
    3172             :  *
    3173             :  * Combines predicate locks for two existing pages.
    3174             :  * Skip if this is a temporary table or toast table.
    3175             :  *
    3176             :  * NOTE: A page combine affects all serializable transactions, even if it
    3177             :  * occurs in the context of another transaction isolation level.
    3178             :  */
    3179             : void
    3180        4702 : PredicateLockPageCombine(Relation relation, BlockNumber oldblkno,
    3181             :                          BlockNumber newblkno)
    3182             : {
    3183             :     /*
    3184             :      * Page combines differ from page splits in that we ought to be able to
    3185             :      * remove the locks on the old page after transferring them to the new
    3186             :      * page, instead of duplicating them. However, because we can't edit other
    3187             :      * backends' local lock tables, removing the old lock would leave them
    3188             :      * with an entry in their LocalPredicateLockHash for a lock they're not
    3189             :      * holding, which isn't acceptable. So we wind up having to do the same
    3190             :      * work as a page split, acquiring a lock on the new page and keeping the
    3191             :      * old page locked too. That can lead to some false positives, but should
    3192             :      * be rare in practice.
    3193             :      */
    3194        4702 :     PredicateLockPageSplit(relation, oldblkno, newblkno);
    3195        4702 : }
    3196             : 
    3197             : /*
    3198             :  * Walk the list of in-progress serializable transactions and find the new
    3199             :  * xmin.
    3200             :  */
    3201             : static void
    3202        1716 : SetNewSxactGlobalXmin(void)
    3203             : {
    3204             :     dlist_iter  iter;
    3205             : 
    3206             :     Assert(LWLockHeldByMe(SerializableXactHashLock));
    3207             : 
    3208        1716 :     PredXact->SxactGlobalXmin = InvalidTransactionId;
    3209        1716 :     PredXact->SxactGlobalXminCount = 0;
    3210             : 
    3211        6512 :     dlist_foreach(iter, &PredXact->activeList)
    3212             :     {
    3213        4796 :         SERIALIZABLEXACT *sxact =
    3214        4796 :             dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
    3215             : 
    3216        4796 :         if (!SxactIsRolledBack(sxact)
    3217        4204 :             && !SxactIsCommitted(sxact)
    3218          34 :             && sxact != OldCommittedSxact)
    3219             :         {
    3220             :             Assert(sxact->xmin != InvalidTransactionId);
    3221          34 :             if (!TransactionIdIsValid(PredXact->SxactGlobalXmin)
    3222           0 :                 || TransactionIdPrecedes(sxact->xmin,
    3223           0 :                                          PredXact->SxactGlobalXmin))
    3224             :             {
    3225          34 :                 PredXact->SxactGlobalXmin = sxact->xmin;
    3226          34 :                 PredXact->SxactGlobalXminCount = 1;
    3227             :             }
    3228           0 :             else if (TransactionIdEquals(sxact->xmin,
    3229             :                                          PredXact->SxactGlobalXmin))
    3230           0 :                 PredXact->SxactGlobalXminCount++;
    3231             :         }
    3232             :     }
    3233             : 
    3234        1716 :     SerialSetActiveSerXmin(PredXact->SxactGlobalXmin);
    3235        1716 : }
    3236             : 
    3237             : /*
    3238             :  *      ReleasePredicateLocks
    3239             :  *
    3240             :  * Releases predicate locks based on completion of the current transaction,
    3241             :  * whether committed or rolled back.  It can also be called for a read only
    3242             :  * transaction when it becomes impossible for the transaction to become
    3243             :  * part of a dangerous structure.
    3244             :  *
    3245             :  * We do nothing unless this is a serializable transaction.
    3246             :  *
    3247             :  * This method must ensure that shared memory hash tables are cleaned
    3248             :  * up in some relatively timely fashion.
    3249             :  *
    3250             :  * If this transaction is committing and is holding any predicate locks,
    3251             :  * it must be added to a list of completed serializable transactions still
    3252             :  * holding locks.
    3253             :  *
    3254             :  * If isReadOnlySafe is true, then predicate locks are being released before
    3255             :  * the end of the transaction because MySerializableXact has been determined
    3256             :  * to be RO_SAFE.  In non-parallel mode we can release it completely, but it
    3257             :  * in parallel mode we partially release the SERIALIZABLEXACT and keep it
    3258             :  * around until the end of the transaction, allowing each backend to clear its
    3259             :  * MySerializableXact variable and benefit from the optimization in its own
    3260             :  * time.
    3261             :  */
    3262             : void
    3263      514260 : ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
    3264             : {
    3265      514260 :     bool        partiallyReleasing = false;
    3266             :     bool        needToClear;
    3267             :     SERIALIZABLEXACT *roXact;
    3268             :     dlist_mutable_iter iter;
    3269             : 
    3270             :     /*
    3271             :      * We can't trust XactReadOnly here, because a transaction which started
    3272             :      * as READ WRITE can show as READ ONLY later, e.g., within
    3273             :      * subtransactions.  We want to flag a transaction as READ ONLY if it
    3274             :      * commits without writing so that de facto READ ONLY transactions get the
    3275             :      * benefit of some RO optimizations, so we will use this local variable to
    3276             :      * get some cleanup logic right which is based on whether the transaction
    3277             :      * was declared READ ONLY at the top level.
    3278             :      */
    3279             :     bool        topLevelIsDeclaredReadOnly;
    3280             : 
    3281             :     /* We can't be both committing and releasing early due to RO_SAFE. */
    3282             :     Assert(!(isCommit && isReadOnlySafe));
    3283             : 
    3284             :     /* Are we at the end of a transaction, that is, a commit or abort? */
    3285      514260 :     if (!isReadOnlySafe)
    3286             :     {
    3287             :         /*
    3288             :          * Parallel workers mustn't release predicate locks at the end of
    3289             :          * their transaction.  The leader will do that at the end of its
    3290             :          * transaction.
    3291             :          */
    3292      514194 :         if (IsParallelWorker())
    3293             :         {
    3294        7776 :             ReleasePredicateLocksLocal();
    3295      511198 :             return;
    3296             :         }
    3297             : 
    3298             :         /*
    3299             :          * By the time the leader in a parallel query reaches end of
    3300             :          * transaction, it has waited for all workers to exit.
    3301             :          */
    3302             :         Assert(!ParallelContextActive());
    3303             : 
    3304             :         /*
    3305             :          * If the leader in a parallel query earlier stashed a partially
    3306             :          * released SERIALIZABLEXACT for final clean-up at end of transaction
    3307             :          * (because workers might still have been accessing it), then it's
    3308             :          * time to restore it.
    3309             :          */
    3310      506418 :         if (SavedSerializableXact != InvalidSerializableXact)
    3311             :         {
    3312             :             Assert(MySerializableXact == InvalidSerializableXact);
    3313           2 :             MySerializableXact = SavedSerializableXact;
    3314           2 :             SavedSerializableXact = InvalidSerializableXact;
    3315             :             Assert(SxactIsPartiallyReleased(MySerializableXact));
    3316             :         }
    3317             :     }
    3318             : 
    3319      506484 :     if (MySerializableXact == InvalidSerializableXact)
    3320             :     {
    3321             :         Assert(LocalPredicateLockHash == NULL);
    3322      503416 :         return;
    3323             :     }
    3324             : 
    3325        3068 :     LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    3326             : 
    3327             :     /*
    3328             :      * If the transaction is committing, but it has been partially released
    3329             :      * already, then treat this as a roll back.  It was marked as rolled back.
    3330             :      */
    3331        3068 :     if (isCommit && SxactIsPartiallyReleased(MySerializableXact))
    3332           4 :         isCommit = false;
    3333             : 
    3334             :     /*
    3335             :      * If we're called in the middle of a transaction because we discovered
    3336             :      * that the SXACT_FLAG_RO_SAFE flag was set, then we'll partially release
    3337             :      * it (that is, release the predicate locks and conflicts, but not the
    3338             :      * SERIALIZABLEXACT itself) if we're the first backend to have noticed.
    3339             :      */
    3340        3068 :     if (isReadOnlySafe && IsInParallelMode())
    3341             :     {
    3342             :         /*
    3343             :          * The leader needs to stash a pointer to it, so that it can
    3344             :          * completely release it at end-of-transaction.
    3345             :          */
    3346          10 :         if (!IsParallelWorker())
    3347           2 :             SavedSerializableXact = MySerializableXact;
    3348             : 
    3349             :         /*
    3350             :          * The first backend to reach this condition will partially release
    3351             :          * the SERIALIZABLEXACT.  All others will just clear their
    3352             :          * backend-local state so that they stop doing SSI checks for the rest
    3353             :          * of the transaction.
    3354             :          */
    3355          10 :         if (SxactIsPartiallyReleased(MySerializableXact))
    3356             :         {
    3357           6 :             LWLockRelease(SerializableXactHashLock);
    3358           6 :             ReleasePredicateLocksLocal();
    3359           6 :             return;
    3360             :         }
    3361             :         else
    3362             :         {
    3363           4 :             MySerializableXact->flags |= SXACT_FLAG_PARTIALLY_RELEASED;
    3364           4 :             partiallyReleasing = true;
    3365             :             /* ... and proceed to perform the partial release below. */
    3366             :         }
    3367             :     }
    3368             :     Assert(!isCommit || SxactIsPrepared(MySerializableXact));
    3369             :     Assert(!isCommit || !SxactIsDoomed(MySerializableXact));
    3370             :     Assert(!SxactIsCommitted(MySerializableXact));
    3371             :     Assert(SxactIsPartiallyReleased(MySerializableXact)
    3372             :            || !SxactIsRolledBack(MySerializableXact));
    3373             : 
    3374             :     /* may not be serializable during COMMIT/ROLLBACK PREPARED */
    3375             :     Assert(MySerializableXact->pid == 0 || IsolationIsSerializable());
    3376             : 
    3377             :     /* We'd better not already be on the cleanup list. */
    3378             :     Assert(!SxactIsOnFinishedList(MySerializableXact));
    3379             : 
    3380        3062 :     topLevelIsDeclaredReadOnly = SxactIsReadOnly(MySerializableXact);
    3381             : 
    3382             :     /*
    3383             :      * We don't hold XidGenLock lock here, assuming that TransactionId is
    3384             :      * atomic!
    3385             :      *
    3386             :      * If this value is changing, we don't care that much whether we get the
    3387             :      * old or new value -- it is just used to determine how far
    3388             :      * SxactGlobalXmin must advance before this transaction can be fully
    3389             :      * cleaned up.  The worst that could happen is we wait for one more
    3390             :      * transaction to complete before freeing some RAM; correctness of visible
    3391             :      * behavior is not affected.
    3392             :      */
    3393        3062 :     MySerializableXact->finishedBefore = XidFromFullTransactionId(ShmemVariableCache->nextXid);
    3394             : 
    3395             :     /*
    3396             :      * If it's not a commit it's either a rollback or a read-only transaction
    3397             :      * flagged SXACT_FLAG_RO_SAFE, and we can clear our locks immediately.
    3398             :      */
    3399        3062 :     if (isCommit)
    3400             :     {
    3401        2420 :         MySerializableXact->flags |= SXACT_FLAG_COMMITTED;
    3402        2420 :         MySerializableXact->commitSeqNo = ++(PredXact->LastSxactCommitSeqNo);
    3403             :         /* Recognize implicit read-only transaction (commit without write). */
    3404        2420 :         if (!MyXactDidWrite)
    3405         466 :             MySerializableXact->flags |= SXACT_FLAG_READ_ONLY;
    3406             :     }
    3407             :     else
    3408             :     {
    3409             :         /*
    3410             :          * The DOOMED flag indicates that we intend to roll back this
    3411             :          * transaction and so it should not cause serialization failures for
    3412             :          * other transactions that conflict with it. Note that this flag might
    3413             :          * already be set, if another backend marked this transaction for
    3414             :          * abort.
    3415             :          *
    3416             :          * The ROLLED_BACK flag further indicates that ReleasePredicateLocks
    3417             :          * has been called, and so the SerializableXact is eligible for
    3418             :          * cleanup. This means it should not be considered when calculating
    3419             :          * SxactGlobalXmin.
    3420             :          */
    3421         642 :         MySerializableXact->flags |= SXACT_FLAG_DOOMED;
    3422         642 :         MySerializableXact->flags |= SXACT_FLAG_ROLLED_BACK;
    3423             : 
    3424             :         /*
    3425             :          * If the transaction was previously prepared, but is now failing due
    3426             :          * to a ROLLBACK PREPARED or (hopefully very rare) error after the
    3427             :          * prepare, clear the prepared flag.  This simplifies conflict
    3428             :          * checking.
    3429             :          */
    3430         642 :         MySerializableXact->flags &= ~SXACT_FLAG_PREPARED;
    3431             :     }
    3432             : 
    3433        3062 :     if (!topLevelIsDeclaredReadOnly)
    3434             :     {
    3435             :         Assert(PredXact->WritableSxactCount > 0);
    3436        2846 :         if (--(PredXact->WritableSxactCount) == 0)
    3437             :         {
    3438             :             /*
    3439             :              * Release predicate locks and rw-conflicts in for all committed
    3440             :              * transactions.  There are no longer any transactions which might
    3441             :              * conflict with the locks and no chance for new transactions to
    3442             :              * overlap.  Similarly, existing conflicts in can't cause pivots,
    3443             :              * and any conflicts in which could have completed a dangerous
    3444             :              * structure would already have caused a rollback, so any
    3445             :              * remaining ones must be benign.
    3446             :              */
    3447        1702 :             PredXact->CanPartialClearThrough = PredXact->LastSxactCommitSeqNo;
    3448             :         }
    3449             :     }
    3450             :     else
    3451             :     {
    3452             :         /*
    3453             :          * Read-only transactions: clear the list of transactions that might
    3454             :          * make us unsafe. Note that we use 'inLink' for the iteration as
    3455             :          * opposed to 'outLink' for the r/w xacts.
    3456             :          */
    3457         300 :         dlist_foreach_modify(iter, &MySerializableXact->possibleUnsafeConflicts)
    3458             :         {
    3459          84 :             RWConflict  possibleUnsafeConflict =
    3460          84 :                 dlist_container(RWConflictData, inLink, iter.cur);
    3461             : 
    3462             :             Assert(!SxactIsReadOnly(possibleUnsafeConflict->sxactOut));
    3463             :             Assert(MySerializableXact == possibleUnsafeConflict->sxactIn);
    3464             : 
    3465          84 :             ReleaseRWConflict(possibleUnsafeConflict);
    3466             :         }
    3467             :     }
    3468             : 
    3469             :     /* Check for conflict out to old committed transactions. */
    3470        3062 :     if (isCommit
    3471        2420 :         && !SxactIsReadOnly(MySerializableXact)
    3472        1954 :         && SxactHasSummaryConflictOut(MySerializableXact))
    3473             :     {
    3474             :         /*
    3475             :          * we don't know which old committed transaction we conflicted with,
    3476             :          * so be conservative and use FirstNormalSerCommitSeqNo here
    3477             :          */
    3478           0 :         MySerializableXact->SeqNo.earliestOutConflictCommit =
    3479             :             FirstNormalSerCommitSeqNo;
    3480           0 :         MySerializableXact->flags |= SXACT_FLAG_CONFLICT_OUT;
    3481             :     }
    3482             : 
    3483             :     /*
    3484             :      * Release all outConflicts to committed transactions.  If we're rolling
    3485             :      * back clear them all.  Set SXACT_FLAG_CONFLICT_OUT if any point to
    3486             :      * previously committed transactions.
    3487             :      */
    3488        4420 :     dlist_foreach_modify(iter, &MySerializableXact->outConflicts)
    3489             :     {
    3490        1358 :         RWConflict  conflict =
    3491        1358 :             dlist_container(RWConflictData, outLink, iter.cur);
    3492             : 
    3493        1358 :         if (isCommit
    3494         902 :             && !SxactIsReadOnly(MySerializableXact)
    3495         686 :             && SxactIsCommitted(conflict->sxactIn))
    3496             :         {
    3497         192 :             if ((MySerializableXact->flags & SXACT_FLAG_CONFLICT_OUT) == 0
    3498           0 :                 || conflict->sxactIn->prepareSeqNo < MySerializableXact->SeqNo.earliestOutConflictCommit)
    3499         192 :                 MySerializableXact->SeqNo.earliestOutConflictCommit = conflict->sxactIn->prepareSeqNo;
    3500         192 :             MySerializableXact->flags |= SXACT_FLAG_CONFLICT_OUT;
    3501             :         }
    3502             : 
    3503        1358 :         if (!isCommit
    3504         902 :             || SxactIsCommitted(conflict->sxactIn)
    3505         666 :             || (conflict->sxactIn->SeqNo.lastCommitBeforeSnapshot >= PredXact->LastSxactCommitSeqNo))
    3506         692 :             ReleaseRWConflict(conflict);
    3507             :     }
    3508             : 
    3509             :     /*
    3510             :      * Release all inConflicts from committed and read-only transactions. If
    3511             :      * we're rolling back, clear them all.
    3512             :      */
    3513        4600 :     dlist_foreach_modify(iter, &MySerializableXact->inConflicts)
    3514             :     {
    3515        1538 :         RWConflict  conflict =
    3516        1538 :             dlist_container(RWConflictData, inLink, iter.cur);
    3517             : 
    3518        1538 :         if (!isCommit
    3519        1198 :             || SxactIsCommitted(conflict->sxactOut)
    3520         830 :             || SxactIsReadOnly(conflict->sxactOut))
    3521         868 :             ReleaseRWConflict(conflict);
    3522             :     }
    3523             : 
    3524        3062 :     if (!topLevelIsDeclaredReadOnly)
    3525             :     {
    3526             :         /*
    3527             :          * Remove ourselves from the list of possible conflicts for concurrent
    3528             :          * READ ONLY transactions, flagging them as unsafe if we have a
    3529             :          * conflict out. If any are waiting DEFERRABLE transactions, wake them
    3530             :          * up if they are known safe or known unsafe.
    3531             :          */
    3532        3026 :         dlist_foreach_modify(iter, &MySerializableXact->possibleUnsafeConflicts)
    3533             :         {
    3534         180 :             RWConflict  possibleUnsafeConflict =
    3535         180 :                 dlist_container(RWConflictData, outLink, iter.cur);
    3536             : 
    3537         180 :             roXact = possibleUnsafeConflict->sxactIn;
    3538             :             Assert(MySerializableXact == possibleUnsafeConflict->sxactOut);
    3539             :             Assert(SxactIsReadOnly(roXact));
    3540             : 
    3541             :             /* Mark conflicted if necessary. */
    3542         180 :             if (isCommit
    3543         176 :                 && MyXactDidWrite
    3544         166 :                 && SxactHasConflictOut(MySerializableXact)
    3545          26 :                 && (MySerializableXact->SeqNo.earliestOutConflictCommit
    3546          26 :                     <= roXact->SeqNo.lastCommitBeforeSnapshot))
    3547             :             {
    3548             :                 /*
    3549             :                  * This releases possibleUnsafeConflict (as well as all other
    3550             :                  * possible conflicts for roXact)
    3551             :                  */
    3552           6 :                 FlagSxactUnsafe(roXact);
    3553             :             }
    3554             :             else
    3555             :             {
    3556         174 :                 ReleaseRWConflict(possibleUnsafeConflict);
    3557             : 
    3558             :                 /*
    3559             :                  * If we were the last possible conflict, flag it safe. The
    3560             :                  * transaction can now safely release its predicate locks (but
    3561             :                  * that transaction's backend has to do that itself).
    3562             :                  */
    3563         174 :                 if (dlist_is_empty(&roXact->possibleUnsafeConflicts))
    3564         130 :                     roXact->flags |= SXACT_FLAG_RO_SAFE;
    3565             :             }
    3566             : 
    3567             :             /*
    3568             :              * Wake up the process for a waiting DEFERRABLE transaction if we
    3569             :              * now know it's either safe or conflicted.
    3570             :              */
    3571         180 :             if (SxactIsDeferrableWaiting(roXact) &&
    3572           2 :                 (SxactIsROUnsafe(roXact) || SxactIsROSafe(roXact)))
    3573           2 :                 ProcSendSignal(roXact->pgprocno);
    3574             :         }
    3575             :     }
    3576             : 
    3577             :     /*
    3578             :      * Check whether it's time to clean up old transactions. This can only be
    3579             :      * done when the last serializable transaction with the oldest xmin among
    3580             :      * serializable transactions completes.  We then find the "new oldest"
    3581             :      * xmin and purge any transactions which finished before this transaction
    3582             :      * was launched.
    3583             :      *
    3584             :      * For parallel queries in read-only transactions, it might run twice. We
    3585             :      * only release the reference on the first call.
    3586             :      */
    3587        3062 :     needToClear = false;
    3588        3062 :     if ((partiallyReleasing ||
    3589        3058 :          !SxactIsPartiallyReleased(MySerializableXact)) &&
    3590        3058 :         TransactionIdEquals(MySerializableXact->xmin,
    3591             :                             PredXact->SxactGlobalXmin))
    3592             :     {
    3593             :         Assert(PredXact->SxactGlobalXminCount > 0);
    3594        3024 :         if (--(PredXact->SxactGlobalXminCount) == 0)
    3595             :         {
    3596        1716 :             SetNewSxactGlobalXmin();
    3597        1716 :             needToClear = true;
    3598             :         }
    3599             :     }
    3600             : 
    3601        3062 :     LWLockRelease(SerializableXactHashLock);
    3602             : 
    3603        3062 :     LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
    3604             : 
    3605             :     /* Add this to the list of transactions to check for later cleanup. */
    3606        3062 :     if (isCommit)
    3607        2420 :         dlist_push_tail(FinishedSerializableTransactions,
    3608        2420 :                         &MySerializableXact->finishedLink);
    3609             : 
    3610             :     /*
    3611             :      * If we're releasing a RO_SAFE transaction in parallel mode, we'll only
    3612             :      * partially release it.  That's necessary because other backends may have
    3613             :      * a reference to it.  The leader will release the SERIALIZABLEXACT itself
    3614             :      * at the end of the transaction after workers have stopped running.
    3615             :      */
    3616        3062 :     if (!isCommit)
    3617         642 :         ReleaseOneSerializableXact(MySerializableXact,
    3618         642 :                                    isReadOnlySafe && IsInParallelMode(),
    3619             :                                    false);
    3620             : 
    3621        3062 :     LWLockRelease(SerializableFinishedListLock);
    3622             : 
    3623        3062 :     if (needToClear)
    3624        1716 :         ClearOldPredicateLocks();
    3625             : 
    3626        3062 :     ReleasePredicateLocksLocal();
    3627             : }
    3628             : 
    3629             : static void
    3630       10844 : ReleasePredicateLocksLocal(void)
    3631             : {
    3632       10844 :     MySerializableXact = InvalidSerializableXact;
    3633       10844 :     MyXactDidWrite = false;
    3634             : 
    3635             :     /* Delete per-transaction lock table */
    3636       10844 :     if (LocalPredicateLockHash != NULL)
    3637             :     {
    3638        3060 :         hash_destroy(LocalPredicateLockHash);
    3639        3060 :         LocalPredicateLockHash = NULL;
    3640             :     }
    3641       10844 : }
    3642             : 
    3643             : /*
    3644             :  * Clear old predicate locks, belonging to committed transactions that are no
    3645             :  * longer interesting to any in-progress transaction.
    3646             :  */
    3647             : static void
    3648        1716 : ClearOldPredicateLocks(void)
    3649             : {
    3650             :     dlist_mutable_iter iter;
    3651             : 
    3652             :     /*
    3653             :      * Loop through finished transactions. They are in commit order, so we can
    3654             :      * stop as soon as we find one that's still interesting.
    3655             :      */
    3656        1716 :     LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
    3657        1716 :     LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    3658        4152 :     dlist_foreach_modify(iter, FinishedSerializableTransactions)
    3659             :     {
    3660        2452 :         SERIALIZABLEXACT *finishedSxact =
    3661        2452 :             dlist_container(SERIALIZABLEXACT, finishedLink, iter.cur);
    3662             : 
    3663        2452 :         if (!TransactionIdIsValid(PredXact->SxactGlobalXmin)
    3664          54 :             || TransactionIdPrecedesOrEquals(finishedSxact->finishedBefore,
    3665          54 :                                              PredXact->SxactGlobalXmin))
    3666             :         {
    3667             :             /*
    3668             :              * This transaction committed before any in-progress transaction
    3669             :              * took its snapshot. It's no longer interesting.
    3670             :              */
    3671        2420 :             LWLockRelease(SerializableXactHashLock);
    3672        2420 :             dlist_delete_thoroughly(&finishedSxact->finishedLink);
    3673        2420 :             ReleaseOneSerializableXact(finishedSxact, false, false);
    3674        2420 :             LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    3675             :         }
    3676          32 :         else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
    3677          32 :                  && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
    3678             :         {
    3679             :             /*
    3680             :              * Any active transactions that took their snapshot before this
    3681             :              * transaction committed are read-only, so we can clear part of
    3682             :              * its state.
    3683             :              */
    3684          16 :             LWLockRelease(SerializableXactHashLock);
    3685             : 
    3686          16 :             if (SxactIsReadOnly(finishedSxact))
    3687             :             {
    3688             :                 /* A read-only transaction can be removed entirely */
    3689           0 :                 dlist_delete_thoroughly(&(finishedSxact->finishedLink));
    3690           0 :                 ReleaseOneSerializableXact(finishedSxact, false, false);
    3691             :             }
    3692             :             else
    3693             :             {
    3694             :                 /*
    3695             :                  * A read-write transaction can only be partially cleared. We
    3696             :                  * need to keep the SERIALIZABLEXACT but can release the
    3697             :                  * SIREAD locks and conflicts in.
    3698             :                  */
    3699          16 :                 ReleaseOneSerializableXact(finishedSxact, true, false);
    3700             :             }
    3701             : 
    3702          16 :             PredXact->HavePartialClearedThrough = finishedSxact->commitSeqNo;
    3703          16 :             LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    3704             :         }
    3705             :         else
    3706             :         {
    3707             :             /* Still interesting. */
    3708             :             break;
    3709             :         }
    3710             :     }
    3711        1716 :     LWLockRelease(SerializableXactHashLock);
    3712             : 
    3713             :     /*
    3714             :      * Loop through predicate locks on dummy transaction for summarized data.
    3715             :      */
    3716        1716 :     LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
    3717        1716 :     dlist_foreach_modify(iter, &OldCommittedSxact->predicateLocks)
    3718             :     {
    3719           0 :         PREDICATELOCK *predlock =
    3720           0 :             dlist_container(PREDICATELOCK, xactLink, iter.cur);
    3721             :         bool        canDoPartialCleanup;
    3722             : 
    3723           0 :         LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    3724             :         Assert(predlock->commitSeqNo != 0);
    3725             :         Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
    3726           0 :         canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
    3727           0 :         LWLockRelease(SerializableXactHashLock);
    3728             : 
    3729             :         /*
    3730             :          * If this lock originally belonged to an old enough transaction, we
    3731             :          * can release it.
    3732             :          */
    3733           0 :         if (canDoPartialCleanup)
    3734             :         {
    3735             :             PREDICATELOCKTAG tag;
    3736             :             PREDICATELOCKTARGET *target;
    3737             :             PREDICATELOCKTARGETTAG targettag;
    3738             :             uint32      targettaghash;
    3739             :             LWLock     *partitionLock;
    3740             : 
    3741           0 :             tag = predlock->tag;
    3742           0 :             target = tag.myTarget;
    3743           0 :             targettag = target->tag;
    3744           0 :             targettaghash = PredicateLockTargetTagHashCode(&targettag);
    3745           0 :             partitionLock = PredicateLockHashPartitionLock(targettaghash);
    3746             : 
    3747           0 :             LWLockAcquire(partitionLock, LW_EXCLUSIVE);
    3748             : 
    3749           0 :             dlist_delete(&(predlock->targetLink));
    3750           0 :             dlist_delete(&(predlock->xactLink));
    3751             : 
    3752           0 :             hash_search_with_hash_value(PredicateLockHash, &tag,
    3753           0 :                                         PredicateLockHashCodeFromTargetHashCode(&tag,
    3754             :                                                                                 targettaghash),
    3755             :                                         HASH_REMOVE, NULL);
    3756           0 :             RemoveTargetIfNoLongerUsed(target, targettaghash);
    3757             : 
    3758           0 :             LWLockRelease(partitionLock);
    3759             :         }
    3760             :     }
    3761             : 
    3762        1716 :     LWLockRelease(SerializablePredicateListLock);
    3763        1716 :     LWLockRelease(SerializableFinishedListLock);
    3764        1716 : }
    3765             : 
    3766             : /*
    3767             :  * This is the normal way to delete anything from any of the predicate
    3768             :  * locking hash tables.  Given a transaction which we know can be deleted:
    3769             :  * delete all predicate locks held by that transaction and any predicate
    3770             :  * lock targets which are now unreferenced by a lock; delete all conflicts
    3771             :  * for the transaction; delete all xid values for the transaction; then
    3772             :  * delete the transaction.
    3773             :  *
    3774             :  * When the partial flag is set, we can release all predicate locks and
    3775             :  * in-conflict information -- we've established that there are no longer
    3776             :  * any overlapping read write transactions for which this transaction could
    3777             :  * matter -- but keep the transaction entry itself and any outConflicts.
    3778             :  *
    3779             :  * When the summarize flag is set, we've run short of room for sxact data
    3780             :  * and must summarize to the SLRU.  Predicate locks are transferred to a
    3781             :  * dummy "old" transaction, with duplicate locks on a single target
    3782             :  * collapsing to a single lock with the "latest" commitSeqNo from among
    3783             :  * the conflicting locks..
    3784             :  */
    3785             : static void
    3786        3078 : ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
    3787             :                            bool summarize)
    3788             : {
    3789             :     SERIALIZABLEXIDTAG sxidtag;
    3790             :     dlist_mutable_iter iter;
    3791             : 
    3792             :     Assert(sxact != NULL);
    3793             :     Assert(SxactIsRolledBack(sxact) || SxactIsCommitted(sxact));
    3794             :     Assert(partial || !SxactIsOnFinishedList(sxact));
    3795             :     Assert(LWLockHeldByMe(SerializableFinishedListLock));
    3796             : 
    3797             :     /*
    3798             :      * First release all the predicate locks held by this xact (or transfer
    3799             :      * them to OldCommittedSxact if summarize is true)
    3800             :      */
    3801        3078 :     LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
    3802        3078 :     if (IsInParallelMode())
    3803           6 :         LWLockAcquire(&sxact->perXactPredicateListLock, LW_EXCLUSIVE);
    3804        8726 :     dlist_foreach_modify(iter, &sxact->predicateLocks)
    3805             :     {
    3806        5648 :         PREDICATELOCK *predlock =
    3807        5648 :             dlist_container(PREDICATELOCK, xactLink, iter.cur);
    3808             :         PREDICATELOCKTAG tag;
    3809             :         PREDICATELOCKTARGET *target;
    3810             :         PREDICATELOCKTARGETTAG targettag;
    3811             :         uint32      targettaghash;
    3812             :         LWLock     *partitionLock;
    3813             : 
    3814        5648 :         tag = predlock->tag;
    3815        5648 :         target = tag.myTarget;
    3816        5648 :         targettag = target->tag;
    3817        5648 :         targettaghash = PredicateLockTargetTagHashCode(&targettag);
    3818        5648 :         partitionLock = PredicateLockHashPartitionLock(targettaghash);
    3819             : 
    3820        5648 :         LWLockAcquire(partitionLock, LW_EXCLUSIVE);
    3821             : 
    3822        5648 :         dlist_delete(&predlock->targetLink);
    3823             : 
    3824        5648 :         hash_search_with_hash_value(PredicateLockHash, &tag,
    3825        5648 :                                     PredicateLockHashCodeFromTargetHashCode(&tag,
    3826             :                                                                             targettaghash),
    3827             :                                     HASH_REMOVE, NULL);
    3828        5648 :         if (summarize)
    3829             :         {
    3830             :             bool        found;
    3831             : 
    3832             :             /* Fold into dummy transaction list. */
    3833           0 :             tag.myXact = OldCommittedSxact;
    3834           0 :             predlock = hash_search_with_hash_value(PredicateLockHash, &tag,
    3835           0 :                                                    PredicateLockHashCodeFromTargetHashCode(&tag,
    3836             :                                                                                            targettaghash),
    3837             :                                                    HASH_ENTER_NULL, &found);
    3838           0 :             if (!predlock)
    3839           0 :                 ereport(ERROR,
    3840             :                         (errcode(ERRCODE_OUT_OF_MEMORY),
    3841             :                          errmsg("out of shared memory"),
    3842             :                          errhint("You might need to increase %s.", "max_pred_locks_per_transaction")));
    3843           0 :             if (found)
    3844             :             {
    3845             :                 Assert(predlock->commitSeqNo != 0);
    3846             :                 Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
    3847           0 :                 if (predlock->commitSeqNo < sxact->commitSeqNo)
    3848           0 :                     predlock->commitSeqNo = sxact->commitSeqNo;
    3849             :             }
    3850             :             else
    3851             :             {
    3852           0 :                 dlist_push_tail(&target->predicateLocks,
    3853             :                                 &predlock->targetLink);
    3854           0 :                 dlist_push_tail(&OldCommittedSxact->predicateLocks,
    3855             :                                 &predlock->xactLink);
    3856           0 :                 predlock->commitSeqNo = sxact->commitSeqNo;
    3857             :             }
    3858             :         }
    3859             :         else
    3860        5648 :             RemoveTargetIfNoLongerUsed(target, targettaghash);
    3861             : 
    3862        5648 :         LWLockRelease(partitionLock);
    3863             :     }
    3864             : 
    3865             :     /*
    3866             :      * Rather than retail removal, just re-init the head after we've run
    3867             :      * through the list.
    3868             :      */
    3869        3078 :     dlist_init(&sxact->predicateLocks);
    3870             : 
    3871        3078 :     if (IsInParallelMode())
    3872           6 :         LWLockRelease(&sxact->perXactPredicateListLock);
    3873        3078 :     LWLockRelease(SerializablePredicateListLock);
    3874             : 
    3875        3078 :     sxidtag.xid = sxact->topXid;
    3876        3078 :     LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    3877             : 
    3878             :     /* Release all outConflicts (unless 'partial' is true) */
    3879        3078 :     if (!partial)
    3880             :     {
    3881        3058 :         dlist_foreach_modify(iter, &sxact->outConflicts)
    3882             :         {
    3883           0 :             RWConflict  conflict =
    3884           0 :                 dlist_container(RWConflictData, outLink, iter.cur);
    3885             : 
    3886           0 :             if (summarize)
    3887           0 :                 conflict->sxactIn->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
    3888           0 :             ReleaseRWConflict(conflict);
    3889             :         }
    3890             :     }
    3891             : 
    3892             :     /* Release all inConflicts. */
    3893        3078 :     dlist_foreach_modify(iter, &sxact->inConflicts)
    3894             :     {
    3895           0 :         RWConflict  conflict =
    3896           0 :             dlist_container(RWConflictData, inLink, iter.cur);
    3897             : 
    3898           0 :         if (summarize)
    3899           0 :             conflict->sxactOut->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
    3900           0 :         ReleaseRWConflict(conflict);
    3901             :     }
    3902             : 
    3903             :     /* Finally, get rid of the xid and the record of the transaction itself. */
    3904        3078 :     if (!partial)
    3905             :     {
    3906        3058 :         if (sxidtag.xid != InvalidTransactionId)
    3907        2526 :             hash_search(SerializableXidHash, &sxidtag, HASH_REMOVE, NULL);
    3908        3058 :         ReleasePredXact(sxact);
    3909             :     }
    3910             : 
    3911        3078 :     LWLockRelease(SerializableXactHashLock);
    3912        3078 : }
    3913             : 
    3914             : /*
    3915             :  * Tests whether the given top level transaction is concurrent with
    3916             :  * (overlaps) our current transaction.
    3917             :  *
    3918             :  * We need to identify the top level transaction for SSI, anyway, so pass
    3919             :  * that to this function to save the overhead of checking the snapshot's
    3920             :  * subxip array.
    3921             :  */
    3922             : static bool
    3923        1064 : XidIsConcurrent(TransactionId xid)
    3924             : {
    3925             :     Snapshot    snap;
    3926             : 
    3927             :     Assert(TransactionIdIsValid(xid));
    3928             :     Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
    3929             : 
    3930        1064 :     snap = GetTransactionSnapshot();
    3931             : 
    3932        1064 :     if (TransactionIdPrecedes(xid, snap->xmin))
    3933           0 :         return false;
    3934             : 
    3935        1064 :     if (TransactionIdFollowsOrEquals(xid, snap->xmax))
    3936        1044 :         return true;
    3937             : 
    3938          20 :     return pg_lfind32(xid, snap->xip, snap->xcnt);
    3939             : }
    3940             : 
    3941             : bool
    3942   195087258 : CheckForSerializableConflictOutNeeded(Relation relation, Snapshot snapshot)
    3943             : {
    3944   195087258 :     if (!SerializationNeededForRead(relation, snapshot))
    3945   195036588 :         return false;
    3946             : 
    3947             :     /* Check if someone else has already decided that we need to die */
    3948       50670 :     if (SxactIsDoomed(MySerializableXact))
    3949             :     {
    3950           0 :         ereport(ERROR,
    3951             :                 (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
    3952             :                  errmsg("could not serialize access due to read/write dependencies among transactions"),
    3953             :                  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
    3954             :                  errhint("The transaction might succeed if retried.")));
    3955             :     }
    3956             : 
    3957       50670 :     return true;
    3958             : }
    3959             : 
    3960             : /*
    3961             :  * CheckForSerializableConflictOut
    3962             :  *      A table AM is reading a tuple that has been modified.  If it determines
    3963             :  *      that the tuple version it is reading is not visible to us, it should
    3964             :  *      pass in the top level xid of the transaction that created it.
    3965             :  *      Otherwise, if it determines that it is visible to us but it has been
    3966             :  *      deleted or there is a newer version available due to an update, it
    3967             :  *      should pass in the top level xid of the modifying transaction.
    3968             :  *
    3969             :  * This function will check for overlap with our own transaction.  If the given
    3970             :  * xid is also serializable and the transactions overlap (i.e., they cannot see
    3971             :  * each other's writes), then we have a conflict out.
    3972             :  */
    3973             : void
    3974        1132 : CheckForSerializableConflictOut(Relation relation, TransactionId xid, Snapshot snapshot)
    3975             : {
    3976             :     SERIALIZABLEXIDTAG sxidtag;
    3977             :     SERIALIZABLEXID *sxid;
    3978             :     SERIALIZABLEXACT *sxact;
    3979             : 
    3980        1132 :     if (!SerializationNeededForRead(relation, snapshot))
    3981         406 :         return;
    3982             : 
    3983             :     /* Check if someone else has already decided that we need to die */
    3984        1132 :     if (SxactIsDoomed(MySerializableXact))
    3985             :     {
    3986           0 :         ereport(ERROR,
    3987             :                 (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
    3988             :                  errmsg("could not serialize access due to read/write dependencies among transactions"),
    3989             :                  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
    3990             :                  errhint("The transaction might succeed if retried.")));
    3991             :     }
    3992             :     Assert(TransactionIdIsValid(xid));
    3993             : 
    3994        1132 :     if (TransactionIdEquals(xid, GetTopTransactionIdIfAny()))
    3995           0 :         return;
    3996             : 
    3997             :     /*
    3998             :      * Find sxact or summarized info for the top level xid.
    3999             :      */
    4000        1132 :     sxidtag.xid = xid;
    4001        1132 :     LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    4002             :     sxid = (SERIALIZABLEXID *)
    4003        1132 :         hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
    4004        1132 :     if (!sxid)
    4005             :     {
    4006             :         /*
    4007             :          * Transaction not found in "normal" SSI structures.  Check whether it
    4008             :          * got pushed out to SLRU storage for "old committed" transactions.
    4009             :          */
    4010             :         SerCommitSeqNo conflictCommitSeqNo;
    4011             : 
    4012          48 :         conflictCommitSeqNo = SerialGetMinConflictCommitSeqNo(xid);
    4013          48 :         if (conflictCommitSeqNo != 0)
    4014             :         {
    4015           0 :             if (conflictCommitSeqNo != InvalidSerCommitSeqNo
    4016           0 :                 && (!SxactIsReadOnly(MySerializableXact)
    4017           0 :                     || conflictCommitSeqNo
    4018           0 :                     <= MySerializableXact->SeqNo.lastCommitBeforeSnapshot))
    4019           0 :                 ereport(ERROR,
    4020             :                         (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
    4021             :                          errmsg("could not serialize access due to read/write dependencies among transactions"),
    4022             :                          errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
    4023             :                          errhint("The transaction might succeed if retried.")));
    4024             : 
    4025           0 :             if (SxactHasSummaryConflictIn(MySerializableXact)
    4026           0 :                 || !dlist_is_empty(&MySerializableXact->inConflicts))
    4027           0 :                 ereport(ERROR,
    4028             :                         (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
    4029             :                          errmsg("could not serialize access due to read/write dependencies among transactions"),
    4030             :                          errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
    4031             :                          errhint("The transaction might succeed if retried.")));
    4032             : 
    4033           0 :             MySerializableXact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
    4034             :         }
    4035             : 
    4036             :         /* It's not serializable or otherwise not important. */
    4037          48 :         LWLockRelease(SerializableXactHashLock);
    4038          48 :         return;
    4039             :     }
    4040        1084 :     sxact = sxid->myXact;
    4041             :     Assert(TransactionIdEquals(sxact->topXid, xid));
    4042        1084 :     if (sxact == MySerializableXact || SxactIsDoomed(sxact))
    4043             :     {
    4044             :         /* Can't conflict with ourself or a transaction that will roll back. */
    4045           8 :         LWLockRelease(SerializableXactHashLock);
    4046           8 :         return;
    4047             :     }
    4048             : 
    4049             :     /*
    4050             :      * We have a conflict out to a transaction which has a conflict out to a
    4051             :      * summarized transaction.  That summarized transaction must have
    4052             :      * committed first, and we can't tell when it committed in relation to our
    4053             :      * snapshot acquisition, so something needs to be canceled.
    4054             :      */
    4055        1076 :     if (SxactHasSummaryConflictOut(sxact))
    4056             :     {
    4057           0 :         if (!SxactIsPrepared(sxact))
    4058             :         {
    4059           0 :             sxact->flags |= SXACT_FLAG_DOOMED;
    4060           0 :             LWLockRelease(SerializableXactHashLock);
    4061           0 :             return;
    4062             :         }
    4063             :         else
    4064             :         {
    4065           0 :             LWLockRelease(SerializableXactHashLock);
    4066           0 :             ereport(ERROR,
    4067             :                     (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
    4068             :                      errmsg("could not serialize access due to read/write dependencies among transactions"),
    4069             :                      errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
    4070             :                      errhint("The transaction might succeed if retried.")));
    4071             :         }
    4072             :     }
    4073             : 
    4074             :     /*
    4075             :      * If this is a read-only transaction and the writing transaction has
    4076             :      * committed, and it doesn't have a rw-conflict to a transaction which
    4077             :      * committed before it, no conflict.
    4078             :      */
    4079        1076 :     if (SxactIsReadOnly(MySerializableXact)
    4080         238 :         && SxactIsCommitted(sxact)
    4081          16 :         && !SxactHasSummaryConflictOut(sxact)
    4082          16 :         && (!SxactHasConflictOut(sxact)
    4083           4 :             || MySerializableXact->SeqNo.lastCommitBeforeSnapshot < sxact->SeqNo.earliestOutConflictCommit))
    4084             :     {
    4085             :         /* Read-only transaction will appear to run first.  No conflict. */
    4086          12 :         LWLockRelease(SerializableXactHashLock);
    4087          12 :         return;
    4088             :     }
    4089             : 
    4090        1064 :     if (!XidIsConcurrent(xid))
    4091             :     {
    4092             :         /* This write was already in our snapshot; no conflict. */
    4093           0 :         LWLockRelease(SerializableXactHashLock);
    4094           0 :         return;
    4095             :     }
    4096             : 
    4097        1064 :     if (RWConflictExists(MySerializableXact, sxact))
    4098             :     {
    4099             :         /* We don't want duplicate conflict records in the list. */
    4100         338 :         LWLockRelease(SerializableXactHashLock);
    4101         338 :         return;
    4102             :     }
    4103             : 
    4104             :     /*
    4105             :      * Flag the conflict.  But first, if this conflict creates a dangerous
    4106             :      * structure, ereport an error.
    4107             :      */
    4108         726 :     FlagRWConflict(MySerializableXact, sxact);
    4109         700 :     LWLockRelease(SerializableXactHashLock);
    4110             : }
    4111             : 
    4112             : /*
    4113             :  * Check a particular target for rw-dependency conflict in. A subroutine of
    4114             :  * CheckForSerializableConflictIn().
    4115             :  */
    4116             : static void
    4117       14956 : CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
    4118             : {
    4119             :     uint32      targettaghash;
    4120             :     LWLock     *partitionLock;
    4121             :     PREDICATELOCKTARGET *target;
    4122       14956 :     PREDICATELOCK *mypredlock = NULL;
    4123             :     PREDICATELOCKTAG mypredlocktag;
    4124             :     dlist_mutable_iter iter;
    4125             : 
    4126             :     Assert(MySerializableXact != InvalidSerializableXact);
    4127             : 
    4128             :     /*
    4129             :      * The same hash and LW lock apply to the lock target and the lock itself.
    4130             :      */
    4131       14956 :     targettaghash = PredicateLockTargetTagHashCode(targettag);
    4132       14956 :     partitionLock = PredicateLockHashPartitionLock(targettaghash);
    4133       14956 :     LWLockAcquire(partitionLock, LW_SHARED);
    4134             :     target = (PREDICATELOCKTARGET *)
    4135       14956 :         hash_search_with_hash_value(PredicateLockTargetHash,
    4136             :                                     targettag, targettaghash,
    4137             :                                     HASH_FIND, NULL);
    4138       14956 :     if (!target)
    4139             :     {
    4140             :         /* Nothing has this target locked; we're done here. */
    4141       11214 :         LWLockRelease(partitionLock);
    4142       11214 :         return;
    4143             :     }
    4144             : 
    4145             :     /*
    4146             :      * Each lock for an overlapping transaction represents a conflict: a
    4147             :      * rw-dependency in to this transaction.
    4148             :      */
    4149        3742 :     LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    4150             : 
    4151        8432 :     dlist_foreach_modify(iter, &target->predicateLocks)
    4152             :     {
    4153        4824 :         PREDICATELOCK *predlock =
    4154        4824 :             dlist_container(PREDICATELOCK, targetLink, iter.cur);
    4155        4824 :         SERIALIZABLEXACT *sxact = predlock->tag.myXact;
    4156             : 
    4157        4824 :         if (sxact == MySerializableXact)
    4158             :         {
    4159             :             /*
    4160             :              * If we're getting a write lock on a tuple, we don't need a
    4161             :              * predicate (SIREAD) lock on the same tuple. We can safely remove
    4162             :              * our SIREAD lock, but we'll defer doing so until after the loop
    4163             :              * because that requires upgrading to an exclusive partition lock.
    4164             :              *
    4165             :              * We can't use this optimization within a subtransaction because
    4166             :              * the subtransaction could roll back, and we would be left
    4167             :              * without any lock at the top level.
    4168             :              */
    4169        3128 :             if (!IsSubTransaction()
    4170        3128 :                 && GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
    4171             :             {
    4172         776 :                 mypredlock = predlock;
    4173         776 :                 mypredlocktag = predlock->tag;
    4174             :             }
    4175             :         }
    4176        1696 :         else if (!SxactIsDoomed(sxact)
    4177        1696 :                  && (!SxactIsCommitted(sxact)
    4178         166 :                      || TransactionIdPrecedes(GetTransactionSnapshot()->xmin,
    4179             :                                               sxact->finishedBefore))
    4180        1678 :                  && !RWConflictExists(sxact, MySerializableXact))
    4181             :         {
    4182         994 :             LWLockRelease(SerializableXactHashLock);
    4183         994 :             LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    4184             : 
    4185             :             /*
    4186             :              * Re-check after getting exclusive lock because the other
    4187             :              * transaction may have flagged a conflict.
    4188             :              */
    4189         994 :             if (!SxactIsDoomed(sxact)
    4190         994 :                 && (!SxactIsCommitted(sxact)
    4191         148 :                     || TransactionIdPrecedes(GetTransactionSnapshot()->xmin,
    4192             :                                              sxact->finishedBefore))
    4193         994 :                 && !RWConflictExists(sxact, MySerializableXact))
    4194             :             {
    4195         994 :                 FlagRWConflict(sxact, MySerializableXact);
    4196             :             }
    4197             : 
    4198         860 :             LWLockRelease(SerializableXactHashLock);
    4199         860 :             LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    4200             :         }
    4201             :     }
    4202        3608 :     LWLockRelease(SerializableXactHashLock);
    4203        3608 :     LWLockRelease(partitionLock);
    4204             : 
    4205             :     /*
    4206             :      * If we found one of our own SIREAD locks to remove, remove it now.
    4207             :      *
    4208             :      * At this point our transaction already has a RowExclusiveLock on the
    4209             :      * relation, so we are OK to drop the predicate lock on the tuple, if
    4210             :      * found, without fearing that another write against the tuple will occur
    4211             :      * before the MVCC information makes it to the buffer.
    4212             :      */
    4213        3608 :     if (mypredlock != NULL)
    4214             :     {
    4215             :         uint32      predlockhashcode;
    4216             :         PREDICATELOCK *rmpredlock;
    4217             : 
    4218         762 :         LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
    4219         762 :         if (IsInParallelMode())
    4220           0 :             LWLockAcquire(&MySerializableXact->perXactPredicateListLock, LW_EXCLUSIVE);
    4221         762 :         LWLockAcquire(partitionLock, LW_EXCLUSIVE);
    4222         762 :         LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    4223             : 
    4224             :         /*
    4225             :          * Remove the predicate lock from shared memory, if it wasn't removed
    4226             :          * while the locks were released.  One way that could happen is from
    4227             :          * autovacuum cleaning up an index.
    4228             :          */
    4229         762 :         predlockhashcode = PredicateLockHashCodeFromTargetHashCode
    4230             :             (&mypredlocktag, targettaghash);
    4231             :         rmpredlock = (PREDICATELOCK *)
    4232         762 :             hash_search_with_hash_value(PredicateLockHash,
    4233             :                                         &mypredlocktag,
    4234             :                                         predlockhashcode,
    4235             :                                         HASH_FIND, NULL);
    4236         762 :         if (rmpredlock != NULL)
    4237             :         {
    4238             :             Assert(rmpredlock == mypredlock);
    4239             : 
    4240         762 :             dlist_delete(&(mypredlock->targetLink));
    4241         762 :             dlist_delete(&(mypredlock->xactLink));
    4242             : 
    4243             :             rmpredlock = (PREDICATELOCK *)
    4244         762 :                 hash_search_with_hash_value(PredicateLockHash,
    4245             :                                             &mypredlocktag,
    4246             :                                             predlockhashcode,
    4247             :                                             HASH_REMOVE, NULL);
    4248             :             Assert(rmpredlock == mypredlock);
    4249             : 
    4250         762 :             RemoveTargetIfNoLongerUsed(target, targettaghash);
    4251             :         }
    4252             : 
    4253         762 :         LWLockRelease(SerializableXactHashLock);
    4254         762 :         LWLockRelease(partitionLock);
    4255         762 :         if (IsInParallelMode())
    4256           0 :             LWLockRelease(&MySerializableXact->perXactPredicateListLock);
    4257         762 :         LWLockRelease(SerializablePredicateListLock);
    4258             : 
    4259         762 :         if (rmpredlock != NULL)
    4260             :         {
    4261             :             /*
    4262             :              * Remove entry in local lock table if it exists. It's OK if it
    4263             :              * doesn't exist; that means the lock was transferred to a new
    4264             :              * target by a different backend.
    4265             :              */
    4266         762 :             hash_search_with_hash_value(LocalPredicateLockHash,
    4267             :                                         targettag, targettaghash,
    4268             :                                         HASH_REMOVE, NULL);
    4269             : 
    4270         762 :             DecrementParentLocks(targettag);
    4271             :         }
    4272             :     }
    4273             : }
    4274             : 
    4275             : /*
    4276             :  * CheckForSerializableConflictIn
    4277             :  *      We are writing the given tuple.  If that indicates a rw-conflict
    4278             :  *      in from another serializable transaction, take appropriate action.
    4279             :  *
    4280             :  * Skip checking for any granularity for which a parameter is missing.
    4281             :  *
    4282             :  * A tuple update or delete is in conflict if we have a predicate lock
    4283             :  * against the relation or page in which the tuple exists, or against the
    4284             :  * tuple itself.
    4285             :  */
    4286             : void
    4287    28665254 : CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
    4288             : {
    4289             :     PREDICATELOCKTARGETTAG targettag;
    4290             : 
    4291    28665254 :     if (!SerializationNeededForWrite(relation))
    4292    28656404 :         return;
    4293             : 
    4294             :     /* Check if someone else has already decided that we need to die */
    4295        8850 :     if (SxactIsDoomed(MySerializableXact))
    4296           2 :         ereport(ERROR,
    4297             :                 (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
    4298             :                  errmsg("could not serialize access due to read/write dependencies among transactions"),
    4299             :                  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
    4300             :                  errhint("The transaction might succeed if retried.")));
    4301             : 
    4302             :     /*
    4303             :      * We're doing a write which might cause rw-conflicts now or later.
    4304             :      * Memorize that fact.
    4305             :      */
    4306        8848 :     MyXactDidWrite = true;
    4307             : 
    4308             :     /*
    4309             :      * It is important that we check for locks from the finest granularity to
    4310             :      * the coarsest granularity, so that granularity promotion doesn't cause
    4311             :      * us to miss a lock.  The new (coarser) lock will be acquired before the
    4312             :      * old (finer) locks are released.
    4313             :      *
    4314             :      * It is not possible to take and hold a lock across the checks for all
    4315             :      * granularities because each target could be in a separate partition.
    4316             :      */
    4317        8848 :     if (tid != NULL)
    4318             :     {
    4319        1286 :         SET_PREDICATELOCKTARGETTAG_TUPLE(targettag,
    4320             :                                          relation->rd_locator.dbOid,
    4321             :                                          relation->rd_id,
    4322             :                                          ItemPointerGetBlockNumber(tid),
    4323             :                                          ItemPointerGetOffsetNumber(tid));
    4324        1286 :         CheckTargetForConflictsIn(&targettag);
    4325             :     }
    4326             : 
    4327        8802 :     if (blkno != InvalidBlockNumber)
    4328             :     {
    4329        4928 :         SET_PREDICATELOCKTARGETTAG_PAGE(targettag,
    4330             :                                         relation->rd_locator.dbOid,
    4331             :                                         relation->rd_id,
    4332             :                                         blkno);
    4333        4928 :         CheckTargetForConflictsIn(&targettag);
    4334             :     }
    4335             : 
    4336        8742 :     SET_PREDICATELOCKTARGETTAG_RELATION(targettag,
    4337             :                                         relation->rd_locator.dbOid,
    4338             :                                         relation->rd_id);
    4339        8742 :     CheckTargetForConflictsIn(&targettag);
    4340             : }
    4341             : 
    4342             : /*
    4343             :  * CheckTableForSerializableConflictIn
    4344             :  *      The entire table is going through a DDL-style logical mass delete
    4345             :  *      like TRUNCATE or DROP TABLE.  If that causes a rw-conflict in from
    4346             :  *      another serializable transaction, take appropriate action.
    4347             :  *
    4348             :  * While these operations do not operate entirely within the bounds of
    4349             :  * snapshot isolation, they can occur inside a serializable transaction, and
    4350             :  * will logically occur after any reads which saw rows which were destroyed
    4351             :  * by these operations, so we do what we can to serialize properly under
    4352             :  * SSI.
    4353             :  *
    4354             :  * The relation passed in must be a heap relation. Any predicate lock of any
    4355             :  * granularity on the heap will cause a rw-conflict in to this transaction.
    4356             :  * Predicate locks on indexes do not matter because they only exist to guard
    4357             :  * against conflicting inserts into the index, and this is a mass *delete*.
    4358             :  * When a table is truncated or dropped, the index will also be truncated
    4359             :  * or dropped, and we'll deal with locks on the index when that happens.
    4360             :  *
    4361             :  * Dropping or truncating a table also needs to drop any existing predicate
    4362             :  * locks on heap tuples or pages, because they're about to go away. This
    4363             :  * should be done before altering the predicate locks because the transaction
    4364             :  * could be rolled back because of a conflict, in which case the lock changes
    4365             :  * are not needed. (At the moment, we don't actually bother to drop the
    4366             :  * existing locks on a dropped or truncated table at the moment. That might
    4367             :  * lead to some false positives, but it doesn't seem worth the trouble.)
    4368             :  */
    4369             : void
    4370       41232 : CheckTableForSerializableConflictIn(Relation relation)
    4371             : {
    4372             :     HASH_SEQ_STATUS seqstat;
    4373             :     PREDICATELOCKTARGET *target;
    4374             :     Oid         dbId;
    4375             :     Oid         heapId;
    4376             :     int         i;
    4377             : 
    4378             :     /*
    4379             :      * Bail out quickly if there are no serializable transactions running.
    4380             :      * It's safe to check this without taking locks because the caller is
    4381             :      * holding an ACCESS EXCLUSIVE lock on the relation.  No new locks which
    4382             :      * would matter here can be acquired while that is held.
    4383             :      */
    4384       41232 :     if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
    4385       41226 :         return;
    4386             : 
    4387         544 :     if (!SerializationNeededForWrite(relation))
    4388         538 :         return;
    4389             : 
    4390             :     /*
    4391             :      * We're doing a write which might cause rw-conflicts now or later.
    4392             :      * Memorize that fact.
    4393             :      */
    4394           6 :     MyXactDidWrite = true;
    4395             : 
    4396             :     Assert(relation->rd_index == NULL); /* not an index relation */
    4397             : 
    4398           6 :     dbId = relation->rd_locator.dbOid;
    4399           6 :     heapId = relation->rd_id;
    4400             : 
    4401           6 :     LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
    4402         102 :     for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
    4403          96 :         LWLockAcquire(PredicateLockHashPartitionLockByIndex(i), LW_SHARED);
    4404           6 :     LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    4405             : 
    4406             :     /* Scan through target list */
    4407           6 :     hash_seq_init(&seqstat, PredicateLockTargetHash);
    4408             : 
    4409          12 :     while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
    4410             :     {
    4411             :         dlist_mutable_iter iter;
    4412             : 
    4413             :         /*
    4414             :          * Check whether this is a target which needs attention.
    4415             :          */
    4416           6 :         if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
    4417           6 :             continue;           /* wrong relation id */
    4418           0 :         if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
    4419           0 :             continue;           /* wrong database id */
    4420             : 
    4421             :         /*
    4422             :          * Loop through locks for this target and flag conflicts.
    4423             :          */
    4424           0 :         dlist_foreach_modify(iter, &target->predicateLocks)
    4425             :         {
    4426           0 :             PREDICATELOCK *predlock =
    4427           0 :                 dlist_container(PREDICATELOCK, targetLink, iter.cur);
    4428             : 
    4429           0 :             if (predlock->tag.myXact != MySerializableXact
    4430           0 :                 && !RWConflictExists(predlock->tag.myXact, MySerializableXact))
    4431             :             {
    4432           0 :                 FlagRWConflict(predlock->tag.myXact, MySerializableXact);
    4433             :             }
    4434             :         }
    4435             :     }
    4436             : 
    4437             :     /* Release locks in reverse order */
    4438           6 :     LWLockRelease(SerializableXactHashLock);
    4439         102 :     for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
    4440          96 :         LWLockRelease(PredicateLockHashPartitionLockByIndex(i));
    4441           6 :     LWLockRelease(SerializablePredicateListLock);
    4442             : }
    4443             : 
    4444             : 
    4445             : /*
    4446             :  * Flag a rw-dependency between two serializable transactions.
    4447             :  *
    4448             :  * The caller is responsible for ensuring that we have a LW lock on
    4449             :  * the transaction hash table.
    4450             :  */
    4451             : static void
    4452        1720 : FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
    4453             : {
    4454             :     Assert(reader != writer);
    4455             : 
    4456             :     /* First, see if this conflict causes failure. */
    4457        1720 :     OnConflict_CheckForSerializationFailure(reader, writer);
    4458             : 
    4459             :     /* Actually do the conflict flagging. */
    4460        1560 :     if (reader == OldCommittedSxact)
    4461           0 :         writer->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
    4462        1560 :     else if (writer == OldCommittedSxact)
    4463           0 :         reader->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
    4464             :     else
    4465        1560 :         SetRWConflict(reader, writer);
    4466        1560 : }
    4467             : 
    4468             : /*----------------------------------------------------------------------------
    4469             :  * We are about to add a RW-edge to the dependency graph - check that we don't
    4470             :  * introduce a dangerous structure by doing so, and abort one of the
    4471             :  * transactions if so.
    4472             :  *
    4473             :  * A serialization failure can only occur if there is a dangerous structure
    4474             :  * in the dependency graph:
    4475             :  *
    4476             :  *      Tin ------> Tpivot ------> Tout
    4477             :  *            rw             rw
    4478             :  *
    4479             :  * Furthermore, Tout must commit first.
    4480             :  *
    4481             :  * One more optimization is that if Tin is declared READ ONLY (or commits
    4482             :  * without writing), we can only have a problem if Tout committed before Tin
    4483             :  * acquired its snapshot.
    4484             :  *----------------------------------------------------------------------------
    4485             :  */
    4486             : static void
    4487        1720 : OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
    4488             :                                         SERIALIZABLEXACT *writer)
    4489             : {
    4490             :     bool        failure;
    4491             : 
    4492             :     Assert(LWLockHeldByMe(SerializableXactHashLock));
    4493             : 
    4494        1720 :     failure = false;
    4495             : 
    4496             :     /*------------------------------------------------------------------------
    4497             :      * Check for already-committed writer with rw-conflict out flagged
    4498             :      * (conflict-flag on W means that T2 committed before W):
    4499             :      *
    4500             :      *      R ------> W ------> T2
    4501             :      *          rw        rw
    4502             :      *
    4503             :      * That is a dangerous structure, so we must abort. (Since the writer
    4504             :      * has already committed, we must be the reader)
    4505             :      *------------------------------------------------------------------------
    4506             :      */
    4507        1720 :     if (SxactIsCommitted(writer)
    4508          36 :         && (SxactHasConflictOut(writer) || SxactHasSummaryConflictOut(writer)))
    4509           4 :         failure = true;
    4510             : 
    4511             :     /*------------------------------------------------------------------------
    4512             :      * Check whether the writer has become a pivot with an out-conflict
    4513             :      * committed transaction (T2), and T2 committed first:
    4514             :      *
    4515             :      *      R ------> W ------> T2
    4516             :      *          rw        rw
    4517             :      *
    4518             :      * Because T2 must've committed first, there is no anomaly if:
    4519             :      * - the reader committed before T2
    4520             :      * - the writer committed before T2
    4521             :      * - the reader is a READ ONLY transaction and the reader was concurrent
    4522             :      *   with T2 (= reader acquired its snapshot before T2 committed)
    4523             :      *
    4524             :      * We also handle the case that T2 is prepared but not yet committed
    4525             :      * here. In that case T2 has already checked for conflicts, so if it
    4526             :      * commits first, making the above conflict real, it's too late for it
    4527             :      * to abort.
    4528             :      *------------------------------------------------------------------------
    4529             :      */
    4530        1720 :     if (!failure && SxactHasSummaryConflictOut(writer))
    4531           0 :         failure = true;
    4532        1720 :     else if (!failure)
    4533             :     {
    4534             :         dlist_iter  iter;
    4535             : 
    4536        2142 :         dlist_foreach(iter, &writer->outConflicts)
    4537             :         {
    4538         576 :             RWConflict  conflict =
    4539         576 :                 dlist_container(RWConflictData, outLink, iter.cur);
    4540         576 :             SERIALIZABLEXACT *t2 = conflict->sxactIn;
    4541             : 
    4542         576 :             if (SxactIsPrepared(t2)
    4543         162 :                 && (!SxactIsCommitted(reader)
    4544         130 :                     || t2->prepareSeqNo <= reader->commitSeqNo)
    4545         162 :                 && (!SxactIsCommitted(writer)
    4546           0 :                     || t2->prepareSeqNo <= writer->commitSeqNo)
    4547         162 :                 && (!SxactIsReadOnly(reader)
    4548          24 :                     || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
    4549             :             {
    4550         150 :                 failure = true;
    4551         150 :                 break;
    4552             :             }
    4553             :         }
    4554             :     }
    4555             : 
    4556             :     /*------------------------------------------------------------------------
    4557             :      * Check whether the reader has become a pivot with a writer
    4558             :      * that's committed (or prepared):
    4559             :      *
    4560             :      *      T0 ------> R ------> W
    4561             :      *           rw        rw
    4562             :      *
    4563             :      * Because W must've committed first for an anomaly to occur, there is no
    4564             :      * anomaly if:
    4565             :      * - T0 committed before the writer
    4566             :      * - T0 is READ ONLY, and overlaps the writer
    4567             :      *------------------------------------------------------------------------
    4568             :      */
    4569        1720 :     if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
    4570             :     {
    4571          36 :         if (SxactHasSummaryConflictIn(reader))
    4572             :         {
    4573           0 :             failure = true;
    4574             :         }
    4575             :         else
    4576             :         {
    4577             :             dlist_iter  iter;
    4578             : 
    4579             :             /*
    4580             :              * The unconstify is needed as we have no const version of
    4581             :              * dlist_foreach().
    4582             :              */
    4583          36 :             dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->inConflicts)
    4584             :             {
    4585          22 :                 const RWConflict conflict =
    4586          22 :                     dlist_container(RWConflictData, inLink, iter.cur);
    4587          22 :                 const SERIALIZABLEXACT *t0 = conflict->sxactOut;
    4588             : 
    4589          22 :                 if (!SxactIsDoomed(t0)
    4590          22 :                     && (!SxactIsCommitted(t0)
    4591          22 :                         || t0->commitSeqNo >= writer->prepareSeqNo)
    4592          22 :                     && (!SxactIsReadOnly(t0)
    4593           0 :                         || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
    4594             :                 {
    4595          22 :                     failure = true;
    4596          22 :                     break;
    4597             :                 }
    4598             :             }
    4599             :         }
    4600             :     }
    4601             : 
    4602        1720 :     if (failure)
    4603             :     {
    4604             :         /*
    4605             :          * We have to kill a transaction to avoid a possible anomaly from
    4606             :          * occurring. If the writer is us, we can just ereport() to cause a
    4607             :          * transaction abort. Otherwise we flag the writer for termination,
    4608             :          * causing it to abort when it tries to commit. However, if the writer
    4609             :          * is a prepared transaction, already prepared, we can't abort it
    4610             :          * anymore, so we have to kill the reader instead.
    4611             :          */
    4612         176 :         if (MySerializableXact == writer)
    4613             :         {
    4614         134 :             LWLockRelease(SerializableXactHashLock);
    4615         134 :             ereport(ERROR,
    4616             :                     (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
    4617             :                      errmsg("could not serialize access due to read/write dependencies among transactions"),
    4618             :                      errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
    4619             :                      errhint("The transaction might succeed if retried.")));
    4620             :         }
    4621          42 :         else if (SxactIsPrepared(writer))
    4622             :         {
    4623          26 :             LWLockRelease(SerializableXactHashLock);
    4624             : 
    4625             :             /* if we're not the writer, we have to be the reader */
    4626             :             Assert(MySerializableXact == reader);
    4627          26 :             ereport(ERROR,
    4628             :                     (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
    4629             :                      errmsg("could not serialize access due to read/write dependencies among transactions"),
    4630             :                      errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
    4631             :                      errhint("The transaction might succeed if retried.")));
    4632             :         }
    4633          16 :         writer->flags |= SXACT_FLAG_DOOMED;
    4634             :     }
    4635        1560 : }
    4636             : 
    4637             : /*
    4638             :  * PreCommit_CheckForSerializationFailure
    4639             :  *      Check for dangerous structures in a serializable transaction
    4640             :  *      at commit.
    4641             :  *
    4642             :  * We're checking for a dangerous structure as each conflict is recorded.
    4643             :  * The only way we could have a problem at commit is if this is the "out"
    4644             :  * side of a pivot, and neither the "in" side nor the pivot has yet
    4645             :  * committed.
    4646             :  *
    4647             :  * If a dangerous structure is found, the pivot (the near conflict) is
    4648             :  * marked for death, because rolling back another transaction might mean
    4649             :  * that we fail without ever making progress.  This transaction is
    4650             :  * committing writes, so letting it commit ensures progress.  If we
    4651             :  * canceled the far conflict, it might immediately fail again on retry.
    4652             :  */
    4653             : void
    4654      470638 : PreCommit_CheckForSerializationFailure(void)
    4655             : {
    4656             :     dlist_iter  near_iter;
    4657             : 
    4658      470638 :     if (MySerializableXact == InvalidSerializableXact)
    4659      467874 :         return;
    4660             : 
    4661             :     Assert(IsolationIsSerializable());
    4662             : 
    4663        2764 :     LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    4664             : 
    4665             :     /*
    4666             :      * Check if someone else has already decided that we need to die.  Since
    4667             :      * we set our own DOOMED flag when partially releasing, ignore in that
    4668             :      * case.
    4669             :      */
    4670        2764 :     if (SxactIsDoomed(MySerializableXact) &&
    4671         312 :         !SxactIsPartiallyReleased(MySerializableXact))
    4672             :     {
    4673         310 :         LWLockRelease(SerializableXactHashLock);
    4674         310 :         ereport(ERROR,
    4675             :                 (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
    4676             :                  errmsg("could not serialize access due to read/write dependencies among transactions"),
    4677             :                  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
    4678             :                  errhint("The transaction might succeed if retried.")));
    4679             :     }
    4680             : 
    4681        3656 :     dlist_foreach(near_iter, &MySerializableXact->inConflicts)
    4682             :     {
    4683        1202 :         RWConflict  nearConflict =
    4684        1202 :             dlist_container(RWConflictData, inLink, near_iter.cur);
    4685             : 
    4686        1202 :         if (!SxactIsCommitted(nearConflict->sxactOut)
    4687         834 :             && !SxactIsDoomed(nearConflict->sxactOut))
    4688             :         {
    4689             :             dlist_iter  far_iter;
    4690             : 
    4691         894 :             dlist_foreach(far_iter, &nearConflict->sxactOut->inConflicts)
    4692             :             {
    4693         356 :                 RWConflict  farConflict =
    4694         356 :                     dlist_container(RWConflictData, inLink, far_iter.cur);
    4695             : 
    4696         356 :                 if (farConflict->sxactOut == MySerializableXact
    4697          84 :                     || (!SxactIsCommitted(farConflict->sxactOut)
    4698          48 :                         && !SxactIsReadOnly(farConflict->sxactOut)
    4699          24 :                         && !SxactIsDoomed(farConflict->sxactOut)))
    4700             :                 {
    4701             :                     /*
    4702             :                      * Normally, we kill the pivot transaction to make sure we
    4703             :                      * make progress if the failing transaction is retried.
    4704             :                      * However, we can't kill it if it's already prepared, so
    4705             :                      * in that case we commit suicide instead.
    4706             :                      */
    4707         296 :                     if (SxactIsPrepared(nearConflict->sxactOut))
    4708             :                     {
    4709           0 :                         LWLockRelease(SerializableXactHashLock);
    4710           0 :                         ereport(ERROR,
    4711             :                                 (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
    4712             :                                  errmsg("could not serialize access due to read/write dependencies among transactions"),
    4713             :                                  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
    4714             :                                  errhint("The transaction might succeed if retried.")));
    4715             :                     }
    4716         296 :                     nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
    4717         296 :                     break;
    4718             :                 }
    4719             :             }
    4720             :         }
    4721             :     }
    4722             : 
    4723        2454 :     MySerializableXact->prepareSeqNo = ++(PredXact->LastSxactCommitSeqNo);
    4724        2454 :     MySerializableXact->flags |= SXACT_FLAG_PREPARED;
    4725             : 
    4726        2454 :     LWLockRelease(SerializableXactHashLock);
    4727             : }
    4728             : 
    4729             : /*------------------------------------------------------------------------*/
    4730             : 
    4731             : /*
    4732             :  * Two-phase commit support
    4733             :  */
    4734             : 
    4735             : /*
    4736             :  * AtPrepare_Locks
    4737             :  *      Do the preparatory work for a PREPARE: make 2PC state file
    4738             :  *      records for all predicate locks currently held.
    4739             :  */
    4740             : void
    4741         770 : AtPrepare_PredicateLocks(void)
    4742             : {
    4743             :     SERIALIZABLEXACT *sxact;
    4744             :     TwoPhasePredicateRecord record;
    4745             :     TwoPhasePredicateXactRecord *xactRecord;
    4746             :     TwoPhasePredicateLockRecord *lockRecord;
    4747             :     dlist_iter  iter;
    4748             : 
    4749         770 :     sxact = MySerializableXact;
    4750         770 :     xactRecord = &(record.data.xactRecord);
    4751         770 :     lockRecord = &(record.data.lockRecord);
    4752             : 
    4753         770 :     if (MySerializableXact == InvalidSerializableXact)
    4754         746 :         return;
    4755             : 
    4756             :     /* Generate an xact record for our SERIALIZABLEXACT */
    4757          24 :     record.type = TWOPHASEPREDICATERECORD_XACT;
    4758          24 :     xactRecord->xmin = MySerializableXact->xmin;
    4759          24 :     xactRecord->flags = MySerializableXact->flags;
    4760             : 
    4761             :     /*
    4762             :      * Note that we don't include the list of conflicts in our out in the
    4763             :      * statefile, because new conflicts can be added even after the
    4764             :      * transaction prepares. We'll just make a conservative assumption during
    4765             :      * recovery instead.
    4766             :      */
    4767             : 
    4768          24 :     RegisterTwoPhaseRecord(TWOPHASE_RM_PREDICATELOCK_ID, 0,
    4769             :                            &record, sizeof(record));
    4770             : 
    4771             :     /*
    4772             :      * Generate a lock record for each lock.
    4773             :      *
    4774             :      * To do this, we need to walk the predicate lock list in our sxact rather
    4775             :      * than using the local predicate lock table because the latter is not
    4776             :      * guaranteed to be accurate.
    4777             :      */
    4778          24 :     LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
    4779             : 
    4780             :     /*
    4781             :      * No need to take sxact->perXactPredicateListLock in parallel mode
    4782             :      * because there cannot be any parallel workers running while we are
    4783             :      * preparing a transaction.
    4784             :      */
    4785             :     Assert(!IsParallelWorker() && !ParallelContextActive());
    4786             : 
    4787          44 :     dlist_foreach(iter, &sxact->predicateLocks)
    4788             :     {
    4789          20 :         PREDICATELOCK *predlock =
    4790          20 :             dlist_container(PREDICATELOCK, xactLink, iter.cur);
    4791             : 
    4792          20 :         record.type = TWOPHASEPREDICATERECORD_LOCK;
    4793          20 :         lockRecord->target = predlock->tag.myTarget->tag;
    4794             : 
    4795          20 :         RegisterTwoPhaseRecord(TWOPHASE_RM_PREDICATELOCK_ID, 0,
    4796             :                                &record, sizeof(record));
    4797             :     }
    4798             : 
    4799          24 :     LWLockRelease(SerializablePredicateListLock);
    4800             : }
    4801             : 
    4802             : /*
    4803             :  * PostPrepare_Locks
    4804             :  *      Clean up after successful PREPARE. Unlike the non-predicate
    4805             :  *      lock manager, we do not need to transfer locks to a dummy
    4806             :  *      PGPROC because our SERIALIZABLEXACT will stay around
    4807             :  *      anyway. We only need to clean up our local state.
    4808             :  */
    4809             : void
    4810         770 : PostPrepare_PredicateLocks(TransactionId xid)
    4811             : {
    4812         770 :     if (MySerializableXact == InvalidSerializableXact)
    4813         746 :         return;
    4814             : 
    4815             :     Assert(SxactIsPrepared(MySerializableXact));
    4816             : 
    4817          24 :     MySerializableXact->pid = 0;
    4818          24 :     MySerializableXact->pgprocno = INVALID_PGPROCNO;
    4819             : 
    4820          24 :     hash_destroy(LocalPredicateLockHash);
    4821          24 :     LocalPredicateLockHash = NULL;
    4822             : 
    4823          24 :     MySerializableXact = InvalidSerializableXact;
    4824          24 :     MyXactDidWrite = false;
    4825             : }
    4826             : 
    4827             : /*
    4828             :  * PredicateLockTwoPhaseFinish
    4829             :  *      Release a prepared transaction's predicate locks once it
    4830             :  *      commits or aborts.
    4831             :  */
    4832             : void
    4833         776 : PredicateLockTwoPhaseFinish(TransactionId xid, bool isCommit)
    4834             : {
    4835             :     SERIALIZABLEXID *sxid;
    4836             :     SERIALIZABLEXIDTAG sxidtag;
    4837             : 
    4838         776 :     sxidtag.xid = xid;
    4839             : 
    4840         776 :     LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    4841             :     sxid = (SERIALIZABLEXID *)
    4842         776 :         hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
    4843         776 :     LWLockRelease(SerializableXactHashLock);
    4844             : 
    4845             :     /* xid will not be found if it wasn't a serializable transaction */
    4846         776 :     if (sxid == NULL)
    4847         752 :         return;
    4848             : 
    4849             :     /* Release its locks */
    4850          24 :     MySerializableXact = sxid->myXact;
    4851          24 :     MyXactDidWrite = true;      /* conservatively assume that we wrote
    4852             :                                  * something */
    4853          24 :     ReleasePredicateLocks(isCommit, false);
    4854             : }
    4855             : 
    4856             : /*
    4857             :  * Re-acquire a predicate lock belonging to a transaction that was prepared.
    4858             :  */
    4859             : void
    4860           0 : predicatelock_twophase_recover(TransactionId xid, uint16 info,
    4861             :                                void *recdata, uint32 len)
    4862             : {
    4863             :     TwoPhasePredicateRecord *record;
    4864             : 
    4865             :     Assert(len == sizeof(TwoPhasePredicateRecord));
    4866             : 
    4867           0 :     record = (TwoPhasePredicateRecord *) recdata;
    4868             : 
    4869             :     Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
    4870             :            (record->type == TWOPHASEPREDICATERECORD_LOCK));
    4871             : 
    4872           0 :     if (record->type == TWOPHASEPREDICATERECORD_XACT)
    4873             :     {
    4874             :         /* Per-transaction record. Set up a SERIALIZABLEXACT. */
    4875             :         TwoPhasePredicateXactRecord *xactRecord;
    4876             :         SERIALIZABLEXACT *sxact;
    4877             :         SERIALIZABLEXID *sxid;
    4878             :         SERIALIZABLEXIDTAG sxidtag;
    4879             :         bool        found;
    4880             : 
    4881           0 :         xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
    4882             : 
    4883           0 :         LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    4884           0 :         sxact = CreatePredXact();
    4885           0 :         if (!sxact)
    4886           0 :             ereport(ERROR,
    4887             :                     (errcode(ERRCODE_OUT_OF_MEMORY),
    4888             :                      errmsg("out of shared memory")));
    4889             : 
    4890             :         /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
    4891           0 :         sxact->vxid.backendId = InvalidBackendId;
    4892           0 :         sxact->vxid.localTransactionId = (LocalTransactionId) xid;
    4893           0 :         sxact->pid = 0;
    4894           0 :         sxact->pgprocno = INVALID_PGPROCNO;
    4895             : 
    4896             :         /* a prepared xact hasn't committed yet */
    4897           0 :         sxact->prepareSeqNo = RecoverySerCommitSeqNo;
    4898           0 :         sxact->commitSeqNo = InvalidSerCommitSeqNo;
    4899           0 :         sxact->finishedBefore = InvalidTransactionId;
    4900             : 
    4901           0 :         sxact->SeqNo.lastCommitBeforeSnapshot = RecoverySerCommitSeqNo;
    4902             : 
    4903             :         /*
    4904             :          * Don't need to track this; no transactions running at the time the
    4905             :          * recovered xact started are still active, except possibly other
    4906             :          * prepared xacts and we don't care whether those are RO_SAFE or not.
    4907             :          */
    4908           0 :         dlist_init(&(sxact->possibleUnsafeConflicts));
    4909             : 
    4910           0 :         dlist_init(&(sxact->predicateLocks));
    4911           0 :         dlist_node_init(&sxact->finishedLink);
    4912             : 
    4913           0 :         sxact->topXid = xid;
    4914           0 :         sxact->xmin = xactRecord->xmin;
    4915           0 :         sxact->flags = xactRecord->flags;
    4916             :         Assert(SxactIsPrepared(sxact));
    4917           0 :         if (!SxactIsReadOnly(sxact))
    4918             :         {
    4919           0 :             ++(PredXact->WritableSxactCount);
    4920             :             Assert(PredXact->WritableSxactCount <=
    4921             :                    (MaxBackends + max_prepared_xacts));
    4922             :         }
    4923             : 
    4924             :         /*
    4925             :          * We don't know whether the transaction had any conflicts or not, so
    4926             :          * we'll conservatively assume that it had both a conflict in and a
    4927             :          * conflict out, and represent that with the summary conflict flags.
    4928             :          */
    4929           0 :         dlist_init(&(sxact->outConflicts));
    4930           0 :         dlist_init(&(sxact->inConflicts));
    4931           0 :         sxact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
    4932           0 :         sxact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
    4933             : 
    4934             :         /* Register the transaction's xid */
    4935           0 :         sxidtag.xid = xid;
    4936           0 :         sxid = (SERIALIZABLEXID *) hash_search(SerializableXidHash,
    4937             :                                                &sxidtag,
    4938             :                                                HASH_ENTER, &found);
    4939             :         Assert(sxid != NULL);
    4940             :         Assert(!found);
    4941           0 :         sxid->myXact = (SERIALIZABLEXACT *) sxact;
    4942             : 
    4943             :         /*
    4944             :          * Update global xmin. Note that this is a special case compared to
    4945             :          * registering a normal transaction, because the global xmin might go
    4946             :          * backwards. That's OK, because until recovery is over we're not
    4947             :          * going to complete any transactions or create any non-prepared
    4948             :          * transactions, so there's no danger of throwing away.
    4949             :          */
    4950           0 :         if ((!TransactionIdIsValid(PredXact->SxactGlobalXmin)) ||
    4951           0 :             (TransactionIdFollows(PredXact->SxactGlobalXmin, sxact->xmin)))
    4952             :         {
    4953           0 :             PredXact->SxactGlobalXmin = sxact->xmin;
    4954           0 :             PredXact->SxactGlobalXminCount = 1;
    4955           0 :             SerialSetActiveSerXmin(sxact->xmin);
    4956             :         }
    4957           0 :         else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
    4958             :         {
    4959             :             Assert(PredXact->SxactGlobalXminCount > 0);
    4960           0 :             PredXact->SxactGlobalXminCount++;
    4961             :         }
    4962             : 
    4963           0 :         LWLockRelease(SerializableXactHashLock);
    4964             :     }
    4965           0 :     else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
    4966             :     {
    4967             :         /* Lock record. Recreate the PREDICATELOCK */
    4968             :         TwoPhasePredicateLockRecord *lockRecord;
    4969             :         SERIALIZABLEXID *sxid;
    4970             :         SERIALIZABLEXACT *sxact;
    4971             :         SERIALIZABLEXIDTAG sxidtag;
    4972             :         uint32      targettaghash;
    4973             : 
    4974           0 :         lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
    4975           0 :         targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
    4976             : 
    4977           0 :         LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    4978           0 :         sxidtag.xid = xid;
    4979             :         sxid = (SERIALIZABLEXID *)
    4980           0 :             hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
    4981           0 :         LWLockRelease(SerializableXactHashLock);
    4982             : 
    4983             :         Assert(sxid != NULL);
    4984           0 :         sxact = sxid->myXact;
    4985             :         Assert(sxact != InvalidSerializableXact);
    4986             : 
    4987           0 :         CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
    4988             :     }
    4989           0 : }
    4990             : 
    4991             : /*
    4992             :  * Prepare to share the current SERIALIZABLEXACT with parallel workers.
    4993             :  * Return a handle object that can be used by AttachSerializableXact() in a
    4994             :  * parallel worker.
    4995             :  */
    4996             : SerializableXactHandle
    4997         804 : ShareSerializableXact(void)
    4998             : {
    4999         804 :     return MySerializableXact;
    5000             : }
    5001             : 
    5002             : /*
    5003             :  * Allow parallel workers to import the leader's SERIALIZABLEXACT.
    5004             :  */
    5005             : void
    5006        2592 : AttachSerializableXact(SerializableXactHandle handle)
    5007             : {
    5008             : 
    5009             :     Assert(MySerializableXact == InvalidSerializableXact);
    5010             : 
    5011        2592 :     MySerializableXact = (SERIALIZABLEXACT *) handle;
    5012        2592 :     if (MySerializableXact != InvalidSerializableXact)
    5013          26 :         CreateLocalPredicateLockHash();
    5014        2592 : }

Generated by: LCOV version 1.14