PostgreSQL Source Code  git master
predicate.c File Reference
#include "postgres.h"
#include "access/parallel.h"
#include "access/slru.h"
#include "access/subtrans.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "port/pg_lfind.h"
#include "storage/bufmgr.h"
#include "storage/predicate.h"
#include "storage/predicate_internals.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
Include dependency graph for predicate.c:

Go to the source code of this file.

Data Structures

struct  SerialControlData
 

Macros

#define TargetTagIsCoveredBy(covered_target, covering_target)
 
#define PredicateLockHashPartition(hashcode)    ((hashcode) % NUM_PREDICATELOCK_PARTITIONS)
 
#define PredicateLockHashPartitionLock(hashcode)
 
#define PredicateLockHashPartitionLockByIndex(i)    (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
 
#define NPREDICATELOCKTARGETENTS()    mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
 
#define SxactIsOnFinishedList(sxact)   (!dlist_node_is_detached(&(sxact)->finishedLink))
 
#define SxactIsCommitted(sxact)   (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)
 
#define SxactIsPrepared(sxact)   (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)
 
#define SxactIsRolledBack(sxact)   (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0)
 
#define SxactIsDoomed(sxact)   (((sxact)->flags & SXACT_FLAG_DOOMED) != 0)
 
#define SxactIsReadOnly(sxact)   (((sxact)->flags & SXACT_FLAG_READ_ONLY) != 0)
 
#define SxactHasSummaryConflictIn(sxact)   (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_IN) != 0)
 
#define SxactHasSummaryConflictOut(sxact)   (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_OUT) != 0)
 
#define SxactHasConflictOut(sxact)   (((sxact)->flags & SXACT_FLAG_CONFLICT_OUT) != 0)
 
#define SxactIsDeferrableWaiting(sxact)   (((sxact)->flags & SXACT_FLAG_DEFERRABLE_WAITING) != 0)
 
#define SxactIsROSafe(sxact)   (((sxact)->flags & SXACT_FLAG_RO_SAFE) != 0)
 
#define SxactIsROUnsafe(sxact)   (((sxact)->flags & SXACT_FLAG_RO_UNSAFE) != 0)
 
#define SxactIsPartiallyReleased(sxact)   (((sxact)->flags & SXACT_FLAG_PARTIALLY_RELEASED) != 0)
 
#define PredicateLockTargetTagHashCode(predicatelocktargettag)    get_hash_value(PredicateLockTargetHash, predicatelocktargettag)
 
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
 
#define SerialSlruCtl   (&SerialSlruCtlData)
 
#define SERIAL_PAGESIZE   BLCKSZ
 
#define SERIAL_ENTRYSIZE   sizeof(SerCommitSeqNo)
 
#define SERIAL_ENTRIESPERPAGE   (SERIAL_PAGESIZE / SERIAL_ENTRYSIZE)
 
#define SERIAL_MAX_PAGE   (MaxTransactionId / SERIAL_ENTRIESPERPAGE)
 
#define SerialNextPage(page)   (((page) >= SERIAL_MAX_PAGE) ? 0 : (page) + 1)
 
#define SerialValue(slotno, xid)
 
#define SerialPage(xid)   (((uint32) (xid)) / SERIAL_ENTRIESPERPAGE)
 

Typedefs

typedef struct SerialControlData SerialControlData
 
typedef struct SerialControlDataSerialControl
 

Functions

static SERIALIZABLEXACTCreatePredXact (void)
 
static void ReleasePredXact (SERIALIZABLEXACT *sxact)
 
static bool RWConflictExists (const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
 
static void SetRWConflict (SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
 
static void SetPossibleUnsafeConflict (SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
 
static void ReleaseRWConflict (RWConflict conflict)
 
static void FlagSxactUnsafe (SERIALIZABLEXACT *sxact)
 
static bool SerialPagePrecedesLogically (int64 page1, int64 page2)
 
static void SerialInit (void)
 
static void SerialAdd (TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
 
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo (TransactionId xid)
 
static void SerialSetActiveSerXmin (TransactionId xid)
 
static uint32 predicatelock_hash (const void *key, Size keysize)
 
static void SummarizeOldestCommittedSxact (void)
 
static Snapshot GetSafeSnapshot (Snapshot origSnapshot)
 
static Snapshot GetSerializableTransactionSnapshotInt (Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
 
static bool PredicateLockExists (const PREDICATELOCKTARGETTAG *targettag)
 
static bool GetParentPredicateLockTag (const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
 
static bool CoarserLockCovers (const PREDICATELOCKTARGETTAG *newtargettag)
 
static void RemoveScratchTarget (bool lockheld)
 
static void RestoreScratchTarget (bool lockheld)
 
static void RemoveTargetIfNoLongerUsed (PREDICATELOCKTARGET *target, uint32 targettaghash)
 
static void DeleteChildTargetLocks (const PREDICATELOCKTARGETTAG *newtargettag)
 
static int MaxPredicateChildLocks (const PREDICATELOCKTARGETTAG *tag)
 
static bool CheckAndPromotePredicateLockRequest (const PREDICATELOCKTARGETTAG *reqtag)
 
static void DecrementParentLocks (const PREDICATELOCKTARGETTAG *targettag)
 
static void CreatePredicateLock (const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
 
static void DeleteLockTarget (PREDICATELOCKTARGET *target, uint32 targettaghash)
 
static bool TransferPredicateLocksToNewTarget (PREDICATELOCKTARGETTAG oldtargettag, PREDICATELOCKTARGETTAG newtargettag, bool removeOld)
 
static void PredicateLockAcquire (const PREDICATELOCKTARGETTAG *targettag)
 
static void DropAllPredicateLocksFromTable (Relation relation, bool transfer)
 
static void SetNewSxactGlobalXmin (void)
 
static void ClearOldPredicateLocks (void)
 
static void ReleaseOneSerializableXact (SERIALIZABLEXACT *sxact, bool partial, bool summarize)
 
static bool XidIsConcurrent (TransactionId xid)
 
static void CheckTargetForConflictsIn (PREDICATELOCKTARGETTAG *targettag)
 
static void FlagRWConflict (SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
 
static void OnConflict_CheckForSerializationFailure (const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
 
static void CreateLocalPredicateLockHash (void)
 
static void ReleasePredicateLocksLocal (void)
 
static bool PredicateLockingNeededForRelation (Relation relation)
 
static bool SerializationNeededForRead (Relation relation, Snapshot snapshot)
 
static bool SerializationNeededForWrite (Relation relation)
 
void CheckPointPredicate (void)
 
void InitPredicateLocks (void)
 
Size PredicateLockShmemSize (void)
 
PredicateLockDataGetPredicateLockStatusData (void)
 
int GetSafeSnapshotBlockingPids (int blocked_pid, int *output, int output_size)
 
Snapshot GetSerializableTransactionSnapshot (Snapshot snapshot)
 
void SetSerializableTransactionSnapshot (Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
 
void RegisterPredicateLockingXid (TransactionId xid)
 
bool PageIsPredicateLocked (Relation relation, BlockNumber blkno)
 
void PredicateLockRelation (Relation relation, Snapshot snapshot)
 
void PredicateLockPage (Relation relation, BlockNumber blkno, Snapshot snapshot)
 
void PredicateLockTID (Relation relation, ItemPointer tid, Snapshot snapshot, TransactionId tuple_xid)
 
void TransferPredicateLocksToHeapRelation (Relation relation)
 
void PredicateLockPageSplit (Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
 
void PredicateLockPageCombine (Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
 
void ReleasePredicateLocks (bool isCommit, bool isReadOnlySafe)
 
bool CheckForSerializableConflictOutNeeded (Relation relation, Snapshot snapshot)
 
void CheckForSerializableConflictOut (Relation relation, TransactionId xid, Snapshot snapshot)
 
void CheckForSerializableConflictIn (Relation relation, ItemPointer tid, BlockNumber blkno)
 
void CheckTableForSerializableConflictIn (Relation relation)
 
void PreCommit_CheckForSerializationFailure (void)
 
void AtPrepare_PredicateLocks (void)
 
void PostPrepare_PredicateLocks (TransactionId xid)
 
void PredicateLockTwoPhaseFinish (TransactionId xid, bool isCommit)
 
void predicatelock_twophase_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
SerializableXactHandle ShareSerializableXact (void)
 
void AttachSerializableXact (SerializableXactHandle handle)
 

Variables

static SlruCtlData SerialSlruCtlData
 
static SerialControl serialControl
 
static SERIALIZABLEXACTOldCommittedSxact
 
int max_predicate_locks_per_xact
 
int max_predicate_locks_per_relation
 
int max_predicate_locks_per_page
 
static PredXactList PredXact
 
static RWConflictPoolHeader RWConflictPool
 
static HTABSerializableXidHash
 
static HTABPredicateLockTargetHash
 
static HTABPredicateLockHash
 
static dlist_headFinishedSerializableTransactions
 
static const PREDICATELOCKTARGETTAG ScratchTargetTag = {0, 0, 0, 0}
 
static uint32 ScratchTargetTagHash
 
static LWLockScratchPartitionLock
 
static HTABLocalPredicateLockHash = NULL
 
static SERIALIZABLEXACTMySerializableXact = InvalidSerializableXact
 
static bool MyXactDidWrite = false
 
static SERIALIZABLEXACTSavedSerializableXact = InvalidSerializableXact
 

Macro Definition Documentation

◆ NPREDICATELOCKTARGETENTS

#define NPREDICATELOCKTARGETENTS ( )     mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))

Definition at line 265 of file predicate.c.

◆ PredicateLockHashCodeFromTargetHashCode

#define PredicateLockHashCodeFromTargetHashCode (   predicatelocktag,
  targethash 
)
Value:
((targethash) ^ ((uint32) PointerGetDatum((predicatelocktag)->myXact)) \
unsigned int uint32
Definition: c.h:495
#define LOG2_NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:102
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322

Definition at line 317 of file predicate.c.

◆ PredicateLockHashPartition

#define PredicateLockHashPartition (   hashcode)     ((hashcode) % NUM_PREDICATELOCK_PARTITIONS)

Definition at line 257 of file predicate.c.

◆ PredicateLockHashPartitionLock

#define PredicateLockHashPartitionLock (   hashcode)
Value:
PredicateLockHashPartition(hashcode)].lock)
LWLockPadded * MainLWLockArray
Definition: lwlock.c:185
#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET
Definition: lwlock.h:109
LWLock lock
Definition: lwlock.h:69

Definition at line 259 of file predicate.c.

◆ PredicateLockHashPartitionLockByIndex

#define PredicateLockHashPartitionLockByIndex (   i)     (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)

Definition at line 262 of file predicate.c.

◆ PredicateLockTargetTagHashCode

#define PredicateLockTargetTagHashCode (   predicatelocktargettag)     get_hash_value(PredicateLockTargetHash, predicatelocktargettag)

Definition at line 304 of file predicate.c.

◆ SERIAL_ENTRIESPERPAGE

#define SERIAL_ENTRIESPERPAGE   (SERIAL_PAGESIZE / SERIAL_ENTRYSIZE)

Definition at line 331 of file predicate.c.

◆ SERIAL_ENTRYSIZE

#define SERIAL_ENTRYSIZE   sizeof(SerCommitSeqNo)

Definition at line 330 of file predicate.c.

◆ SERIAL_MAX_PAGE

#define SERIAL_MAX_PAGE   (MaxTransactionId / SERIAL_ENTRIESPERPAGE)

Definition at line 336 of file predicate.c.

◆ SERIAL_PAGESIZE

#define SERIAL_PAGESIZE   BLCKSZ

Definition at line 329 of file predicate.c.

◆ SerialNextPage

#define SerialNextPage (   page)    (((page) >= SERIAL_MAX_PAGE) ? 0 : (page) + 1)

Definition at line 338 of file predicate.c.

◆ SerialPage

#define SerialPage (   xid)    (((uint32) (xid)) / SERIAL_ENTRIESPERPAGE)

Definition at line 344 of file predicate.c.

◆ SerialSlruCtl

#define SerialSlruCtl   (&SerialSlruCtlData)

Definition at line 327 of file predicate.c.

◆ SerialValue

#define SerialValue (   slotno,
  xid 
)
Value:
(*((SerCommitSeqNo *) \
(SerialSlruCtl->shared->page_buffer[slotno] + \
#define SERIAL_ENTRYSIZE
Definition: predicate.c:330
#define SERIAL_ENTRIESPERPAGE
Definition: predicate.c:331
#define SerialSlruCtl
Definition: predicate.c:327
uint64 SerCommitSeqNo

Definition at line 340 of file predicate.c.

◆ SxactHasConflictOut

#define SxactHasConflictOut (   sxact)    (((sxact)->flags & SXACT_FLAG_CONFLICT_OUT) != 0)

Definition at line 290 of file predicate.c.

◆ SxactHasSummaryConflictIn

#define SxactHasSummaryConflictIn (   sxact)    (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_IN) != 0)

Definition at line 283 of file predicate.c.

◆ SxactHasSummaryConflictOut

#define SxactHasSummaryConflictOut (   sxact)    (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_OUT) != 0)

Definition at line 284 of file predicate.c.

◆ SxactIsCommitted

#define SxactIsCommitted (   sxact)    (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)

Definition at line 278 of file predicate.c.

◆ SxactIsDeferrableWaiting

#define SxactIsDeferrableWaiting (   sxact)    (((sxact)->flags & SXACT_FLAG_DEFERRABLE_WAITING) != 0)

Definition at line 291 of file predicate.c.

◆ SxactIsDoomed

#define SxactIsDoomed (   sxact)    (((sxact)->flags & SXACT_FLAG_DOOMED) != 0)

Definition at line 281 of file predicate.c.

◆ SxactIsOnFinishedList

#define SxactIsOnFinishedList (   sxact)    (!dlist_node_is_detached(&(sxact)->finishedLink))

Definition at line 268 of file predicate.c.

◆ SxactIsPartiallyReleased

#define SxactIsPartiallyReleased (   sxact)    (((sxact)->flags & SXACT_FLAG_PARTIALLY_RELEASED) != 0)

Definition at line 294 of file predicate.c.

◆ SxactIsPrepared

#define SxactIsPrepared (   sxact)    (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)

Definition at line 279 of file predicate.c.

◆ SxactIsReadOnly

#define SxactIsReadOnly (   sxact)    (((sxact)->flags & SXACT_FLAG_READ_ONLY) != 0)

Definition at line 282 of file predicate.c.

◆ SxactIsRolledBack

#define SxactIsRolledBack (   sxact)    (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0)

Definition at line 280 of file predicate.c.

◆ SxactIsROSafe

#define SxactIsROSafe (   sxact)    (((sxact)->flags & SXACT_FLAG_RO_SAFE) != 0)

Definition at line 292 of file predicate.c.

◆ SxactIsROUnsafe

#define SxactIsROUnsafe (   sxact)    (((sxact)->flags & SXACT_FLAG_RO_UNSAFE) != 0)

Definition at line 293 of file predicate.c.

◆ TargetTagIsCoveredBy

#define TargetTagIsCoveredBy (   covered_target,
  covering_target 
)
Value:
((GET_PREDICATELOCKTARGETTAG_RELATION(covered_target) == /* (2) */ \
GET_PREDICATELOCKTARGETTAG_RELATION(covering_target)) \
&& (GET_PREDICATELOCKTARGETTAG_OFFSET(covering_target) == \
InvalidOffsetNumber) /* (3) */ \
&& (((GET_PREDICATELOCKTARGETTAG_OFFSET(covered_target) != \
InvalidOffsetNumber) /* (4a) */ \
&& (GET_PREDICATELOCKTARGETTAG_PAGE(covering_target) == \
GET_PREDICATELOCKTARGETTAG_PAGE(covered_target))) \
|| ((GET_PREDICATELOCKTARGETTAG_PAGE(covering_target) == \
InvalidBlockNumber) /* (4b) */ \
&& (GET_PREDICATELOCKTARGETTAG_PAGE(covered_target) \
&& (GET_PREDICATELOCKTARGETTAG_DB(covered_target) == /* (1) */ \
GET_PREDICATELOCKTARGETTAG_DB(covering_target)))
#define InvalidBlockNumber
Definition: block.h:33
#define InvalidOffsetNumber
Definition: off.h:26
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
#define GET_PREDICATELOCKTARGETTAG_PAGE(locktag)
#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag)

Definition at line 234 of file predicate.c.

Typedef Documentation

◆ SerialControl

Definition at line 353 of file predicate.c.

◆ SerialControlData

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4760 of file predicate.c.

4761 {
4762  SERIALIZABLEXACT *sxact;
4763  TwoPhasePredicateRecord record;
4764  TwoPhasePredicateXactRecord *xactRecord;
4765  TwoPhasePredicateLockRecord *lockRecord;
4766  dlist_iter iter;
4767 
4768  sxact = MySerializableXact;
4769  xactRecord = &(record.data.xactRecord);
4770  lockRecord = &(record.data.lockRecord);
4771 
4773  return;
4774 
4775  /* Generate an xact record for our SERIALIZABLEXACT */
4777  xactRecord->xmin = MySerializableXact->xmin;
4778  xactRecord->flags = MySerializableXact->flags;
4779 
4780  /*
4781  * Note that we don't include the list of conflicts in our out in the
4782  * statefile, because new conflicts can be added even after the
4783  * transaction prepares. We'll just make a conservative assumption during
4784  * recovery instead.
4785  */
4786 
4788  &record, sizeof(record));
4789 
4790  /*
4791  * Generate a lock record for each lock.
4792  *
4793  * To do this, we need to walk the predicate lock list in our sxact rather
4794  * than using the local predicate lock table because the latter is not
4795  * guaranteed to be accurate.
4796  */
4797  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4798 
4799  /*
4800  * No need to take sxact->perXactPredicateListLock in parallel mode
4801  * because there cannot be any parallel workers running while we are
4802  * preparing a transaction.
4803  */
4805 
4806  dlist_foreach(iter, &sxact->predicateLocks)
4807  {
4808  PREDICATELOCK *predlock =
4809  dlist_container(PREDICATELOCK, xactLink, iter.cur);
4810 
4812  lockRecord->target = predlock->tag.myTarget->tag;
4813 
4815  &record, sizeof(record));
4816  }
4817 
4818  LWLockRelease(SerializablePredicateListLock);
4819 }
bool ParallelContextActive(void)
Definition: parallel.c:1006
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
#define IsParallelWorker()
Definition: parallel.h:61
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_SHARED
Definition: lwlock.h:117
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:422
@ TWOPHASEPREDICATERECORD_XACT
@ TWOPHASEPREDICATERECORD_LOCK
#define InvalidSerializableXact
PREDICATELOCKTARGET * myTarget
PREDICATELOCKTARGETTAG tag
PREDICATELOCKTAG tag
PREDICATELOCKTARGETTAG target
TwoPhasePredicateRecordType type
union TwoPhasePredicateRecord::@111 data
TwoPhasePredicateLockRecord lockRecord
TwoPhasePredicateXactRecord xactRecord
dlist_node * cur
Definition: ilist.h:179
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1295
#define TWOPHASE_RM_PREDICATELOCK_ID
Definition: twophase_rmgr.h:28

References Assert(), dlist_iter::cur, TwoPhasePredicateRecord::data, dlist_container, dlist_foreach, SERIALIZABLEXACT::flags, TwoPhasePredicateXactRecord::flags, InvalidSerializableXact, IsParallelWorker, TwoPhasePredicateRecord::lockRecord, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myTarget, ParallelContextActive(), SERIALIZABLEXACT::predicateLocks, RegisterTwoPhaseRecord(), PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, TwoPhasePredicateLockRecord::target, TWOPHASE_RM_PREDICATELOCK_ID, TWOPHASEPREDICATERECORD_LOCK, TWOPHASEPREDICATERECORD_XACT, TwoPhasePredicateRecord::type, TwoPhasePredicateRecord::xactRecord, SERIALIZABLEXACT::xmin, and TwoPhasePredicateXactRecord::xmin.

Referenced by PrepareTransaction().

◆ AttachSerializableXact()

void AttachSerializableXact ( SerializableXactHandle  handle)

Definition at line 5025 of file predicate.c.

5026 {
5027 
5029 
5030  MySerializableXact = (SERIALIZABLEXACT *) handle;
5033 }
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1910

References Assert(), CreateLocalPredicateLockHash(), InvalidSerializableXact, and MySerializableXact.

Referenced by ParallelWorkerMain().

◆ CheckAndPromotePredicateLockRequest()

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2296 of file predicate.c.

2297 {
2298  PREDICATELOCKTARGETTAG targettag,
2299  nexttag,
2300  promotiontag;
2301  LOCALPREDICATELOCK *parentlock;
2302  bool found,
2303  promote;
2304 
2305  promote = false;
2306 
2307  targettag = *reqtag;
2308 
2309  /* check parents iteratively */
2310  while (GetParentPredicateLockTag(&targettag, &nexttag))
2311  {
2312  targettag = nexttag;
2314  &targettag,
2315  HASH_ENTER,
2316  &found);
2317  if (!found)
2318  {
2319  parentlock->held = false;
2320  parentlock->childLocks = 1;
2321  }
2322  else
2323  parentlock->childLocks++;
2324 
2325  if (parentlock->childLocks >
2326  MaxPredicateChildLocks(&targettag))
2327  {
2328  /*
2329  * We should promote to this parent lock. Continue to check its
2330  * ancestors, however, both to get their child counts right and to
2331  * check whether we should just go ahead and promote to one of
2332  * them.
2333  */
2334  promotiontag = targettag;
2335  promote = true;
2336  }
2337  }
2338 
2339  if (promote)
2340  {
2341  /* acquire coarsest ancestor eligible for promotion */
2342  PredicateLockAcquire(&promotiontag);
2343  return true;
2344  }
2345  else
2346  return false;
2347 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
@ HASH_ENTER
Definition: hsearch.h:114
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2487
static HTAB * LocalPredicateLockHash
Definition: predicate.c:415
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:2042
static int MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag)
Definition: predicate.c:2259

References LOCALPREDICATELOCK::childLocks, GetParentPredicateLockTag(), HASH_ENTER, hash_search(), LOCALPREDICATELOCK::held, LocalPredicateLockHash, MaxPredicateChildLocks(), and PredicateLockAcquire().

Referenced by PredicateLockAcquire().

◆ CheckForSerializableConflictIn()

void CheckForSerializableConflictIn ( Relation  relation,
ItemPointer  tid,
BlockNumber  blkno 
)

Definition at line 4306 of file predicate.c.

4307 {
4308  PREDICATELOCKTARGETTAG targettag;
4309 
4310  if (!SerializationNeededForWrite(relation))
4311  return;
4312 
4313  /* Check if someone else has already decided that we need to die */
4315  ereport(ERROR,
4317  errmsg("could not serialize access due to read/write dependencies among transactions"),
4318  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4319  errhint("The transaction might succeed if retried.")));
4320 
4321  /*
4322  * We're doing a write which might cause rw-conflicts now or later.
4323  * Memorize that fact.
4324  */
4325  MyXactDidWrite = true;
4326 
4327  /*
4328  * It is important that we check for locks from the finest granularity to
4329  * the coarsest granularity, so that granularity promotion doesn't cause
4330  * us to miss a lock. The new (coarser) lock will be acquired before the
4331  * old (finer) locks are released.
4332  *
4333  * It is not possible to take and hold a lock across the checks for all
4334  * granularities because each target could be in a separate partition.
4335  */
4336  if (tid != NULL)
4337  {
4339  relation->rd_locator.dbOid,
4340  relation->rd_id,
4343  CheckTargetForConflictsIn(&targettag);
4344  }
4345 
4346  if (blkno != InvalidBlockNumber)
4347  {
4349  relation->rd_locator.dbOid,
4350  relation->rd_id,
4351  blkno);
4352  CheckTargetForConflictsIn(&targettag);
4353  }
4354 
4356  relation->rd_locator.dbOid,
4357  relation->rd_id);
4358  CheckTargetForConflictsIn(&targettag);
4359 }
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1235
int errhint(const char *fmt,...)
Definition: elog.c:1322
int errcode(int sqlerrcode)
Definition: elog.c:860
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition: itemptr.h:124
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition: itemptr.h:103
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:76
static bool MyXactDidWrite
Definition: predicate.c:423
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:561
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4136
#define SxactIsDoomed(sxact)
Definition: predicate.c:281
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag, dboid, reloid)
#define SET_PREDICATELOCKTARGETTAG_TUPLE(locktag, dboid, reloid, blocknum, offnum)
Oid rd_id
Definition: rel.h:113
RelFileLocator rd_locator
Definition: rel.h:57

References CheckTargetForConflictsIn(), RelFileLocator::dbOid, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, InvalidBlockNumber, ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), MySerializableXact, MyXactDidWrite, RelationData::rd_id, RelationData::rd_locator, SerializationNeededForWrite(), SET_PREDICATELOCKTARGETTAG_PAGE, SET_PREDICATELOCKTARGETTAG_RELATION, SET_PREDICATELOCKTARGETTAG_TUPLE, and SxactIsDoomed.

Referenced by _bt_check_unique(), _bt_doinsert(), _hash_doinsert(), ginEntryInsert(), ginFindLeafPage(), ginHeapTupleFastInsert(), gistinserttuples(), heap_delete(), heap_insert(), heap_multi_insert(), heap_update(), and index_insert().

◆ CheckForSerializableConflictOut()

void CheckForSerializableConflictOut ( Relation  relation,
TransactionId  xid,
Snapshot  snapshot 
)

Definition at line 3993 of file predicate.c.

3994 {
3995  SERIALIZABLEXIDTAG sxidtag;
3996  SERIALIZABLEXID *sxid;
3997  SERIALIZABLEXACT *sxact;
3998 
3999  if (!SerializationNeededForRead(relation, snapshot))
4000  return;
4001 
4002  /* Check if someone else has already decided that we need to die */
4004  {
4005  ereport(ERROR,
4007  errmsg("could not serialize access due to read/write dependencies among transactions"),
4008  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4009  errhint("The transaction might succeed if retried.")));
4010  }
4012 
4014  return;
4015 
4016  /*
4017  * Find sxact or summarized info for the top level xid.
4018  */
4019  sxidtag.xid = xid;
4020  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4021  sxid = (SERIALIZABLEXID *)
4022  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4023  if (!sxid)
4024  {
4025  /*
4026  * Transaction not found in "normal" SSI structures. Check whether it
4027  * got pushed out to SLRU storage for "old committed" transactions.
4028  */
4029  SerCommitSeqNo conflictCommitSeqNo;
4030 
4031  conflictCommitSeqNo = SerialGetMinConflictCommitSeqNo(xid);
4032  if (conflictCommitSeqNo != 0)
4033  {
4034  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4036  || conflictCommitSeqNo
4038  ereport(ERROR,
4040  errmsg("could not serialize access due to read/write dependencies among transactions"),
4041  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4042  errhint("The transaction might succeed if retried.")));
4043 
4046  ereport(ERROR,
4048  errmsg("could not serialize access due to read/write dependencies among transactions"),
4049  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4050  errhint("The transaction might succeed if retried.")));
4051 
4053  }
4054 
4055  /* It's not serializable or otherwise not important. */
4056  LWLockRelease(SerializableXactHashLock);
4057  return;
4058  }
4059  sxact = sxid->myXact;
4060  Assert(TransactionIdEquals(sxact->topXid, xid));
4061  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4062  {
4063  /* Can't conflict with ourself or a transaction that will roll back. */
4064  LWLockRelease(SerializableXactHashLock);
4065  return;
4066  }
4067 
4068  /*
4069  * We have a conflict out to a transaction which has a conflict out to a
4070  * summarized transaction. That summarized transaction must have
4071  * committed first, and we can't tell when it committed in relation to our
4072  * snapshot acquisition, so something needs to be canceled.
4073  */
4074  if (SxactHasSummaryConflictOut(sxact))
4075  {
4076  if (!SxactIsPrepared(sxact))
4077  {
4078  sxact->flags |= SXACT_FLAG_DOOMED;
4079  LWLockRelease(SerializableXactHashLock);
4080  return;
4081  }
4082  else
4083  {
4084  LWLockRelease(SerializableXactHashLock);
4085  ereport(ERROR,
4087  errmsg("could not serialize access due to read/write dependencies among transactions"),
4088  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4089  errhint("The transaction might succeed if retried.")));
4090  }
4091  }
4092 
4093  /*
4094  * If this is a read-only transaction and the writing transaction has
4095  * committed, and it doesn't have a rw-conflict to a transaction which
4096  * committed before it, no conflict.
4097  */
4099  && SxactIsCommitted(sxact)
4100  && !SxactHasSummaryConflictOut(sxact)
4101  && (!SxactHasConflictOut(sxact)
4103  {
4104  /* Read-only transaction will appear to run first. No conflict. */
4105  LWLockRelease(SerializableXactHashLock);
4106  return;
4107  }
4108 
4109  if (!XidIsConcurrent(xid))
4110  {
4111  /* This write was already in our snapshot; no conflict. */
4112  LWLockRelease(SerializableXactHashLock);
4113  return;
4114  }
4115 
4117  {
4118  /* We don't want duplicate conflict records in the list. */
4119  LWLockRelease(SerializableXactHashLock);
4120  return;
4121  }
4122 
4123  /*
4124  * Flag the conflict. But first, if this conflict creates a dangerous
4125  * structure, ereport an error.
4126  */
4128  LWLockRelease(SerializableXactHashLock);
4129 }
@ HASH_FIND
Definition: hsearch.h:113
static bool dlist_is_empty(const dlist_head *head)
Definition: ilist.h:336
@ LW_EXCLUSIVE
Definition: lwlock.h:116
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:611
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:517
#define SxactIsCommitted(sxact)
Definition: predicate.c:278
#define SxactIsReadOnly(sxact)
Definition: predicate.c:282
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:283
#define SxactHasConflictOut(sxact)
Definition: predicate.c:290
#define SxactIsPrepared(sxact)
Definition: predicate.c:279
static HTAB * SerializableXidHash
Definition: predicate.c:397
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4471
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:929
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:3942
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:284
#define InvalidSerCommitSeqNo
#define SXACT_FLAG_DOOMED
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
SerCommitSeqNo lastCommitBeforeSnapshot
SerCommitSeqNo earliestOutConflictCommit
union SERIALIZABLEXACT::@110 SeqNo
SERIALIZABLEXACT * myXact
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:432

References Assert(), dlist_is_empty(), SERIALIZABLEXACT::earliestOutConflictCommit, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, FlagRWConflict(), SERIALIZABLEXACT::flags, GetTopTransactionIdIfAny(), HASH_FIND, hash_search(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXID::myXact, RWConflictExists(), SERIALIZABLEXACT::SeqNo, SerialGetMinConflictCommitSeqNo(), SerializableXidHash, SerializationNeededForRead(), SXACT_FLAG_DOOMED, SXACT_FLAG_SUMMARY_CONFLICT_OUT, SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, SERIALIZABLEXACT::topXid, TransactionIdEquals, TransactionIdIsValid, SERIALIZABLEXIDTAG::xid, and XidIsConcurrent().

Referenced by HeapCheckForSerializableConflictOut().

◆ CheckForSerializableConflictOutNeeded()

bool CheckForSerializableConflictOutNeeded ( Relation  relation,
Snapshot  snapshot 
)

Definition at line 3961 of file predicate.c.

3962 {
3963  if (!SerializationNeededForRead(relation, snapshot))
3964  return false;
3965 
3966  /* Check if someone else has already decided that we need to die */
3968  {
3969  ereport(ERROR,
3971  errmsg("could not serialize access due to read/write dependencies among transactions"),
3972  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
3973  errhint("The transaction might succeed if retried.")));
3974  }
3975 
3976  return true;
3977 }

References ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, MySerializableXact, SerializationNeededForRead(), and SxactIsDoomed.

Referenced by HeapCheckForSerializableConflictOut().

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 1021 of file predicate.c.

1022 {
1023  int truncateCutoffPage;
1024 
1025  LWLockAcquire(SerialControlLock, LW_EXCLUSIVE);
1026 
1027  /* Exit quickly if the SLRU is currently not in use. */
1028  if (serialControl->headPage < 0)
1029  {
1030  LWLockRelease(SerialControlLock);
1031  return;
1032  }
1033 
1035  {
1036  int tailPage;
1037 
1038  tailPage = SerialPage(serialControl->tailXid);
1039 
1040  /*
1041  * It is possible for the tailXid to be ahead of the headXid. This
1042  * occurs if we checkpoint while there are in-progress serializable
1043  * transaction(s) advancing the tail but we are yet to summarize the
1044  * transactions. In this case, we cutoff up to the headPage and the
1045  * next summary will advance the headXid.
1046  */
1048  {
1049  /* We can truncate the SLRU up to the page containing tailXid */
1050  truncateCutoffPage = tailPage;
1051  }
1052  else
1053  truncateCutoffPage = serialControl->headPage;
1054  }
1055  else
1056  {
1057  /*----------
1058  * The SLRU is no longer needed. Truncate to head before we set head
1059  * invalid.
1060  *
1061  * XXX: It's possible that the SLRU is not needed again until XID
1062  * wrap-around has happened, so that the segment containing headPage
1063  * that we leave behind will appear to be new again. In that case it
1064  * won't be removed until XID horizon advances enough to make it
1065  * current again.
1066  *
1067  * XXX: This should happen in vac_truncate_clog(), not in checkpoints.
1068  * Consider this scenario, starting from a system with no in-progress
1069  * transactions and VACUUM FREEZE having maximized oldestXact:
1070  * - Start a SERIALIZABLE transaction.
1071  * - Start, finish, and summarize a SERIALIZABLE transaction, creating
1072  * one SLRU page.
1073  * - Consume XIDs to reach xidStopLimit.
1074  * - Finish all transactions. Due to the long-running SERIALIZABLE
1075  * transaction, earlier checkpoints did not touch headPage. The
1076  * next checkpoint will change it, but that checkpoint happens after
1077  * the end of the scenario.
1078  * - VACUUM to advance XID limits.
1079  * - Consume ~2M XIDs, crossing the former xidWrapLimit.
1080  * - Start, finish, and summarize a SERIALIZABLE transaction.
1081  * SerialAdd() declines to create the targetPage, because headPage
1082  * is not regarded as in the past relative to that targetPage. The
1083  * transaction instigating the summarize fails in
1084  * SimpleLruReadPage().
1085  */
1086  truncateCutoffPage = serialControl->headPage;
1087  serialControl->headPage = -1;
1088  }
1089 
1090  LWLockRelease(SerialControlLock);
1091 
1092  /*
1093  * Truncate away pages that are no longer required. Note that no
1094  * additional locking is required, because this is only called as part of
1095  * a checkpoint, and the validity limits have already been determined.
1096  */
1097  SimpleLruTruncate(SerialSlruCtl, truncateCutoffPage);
1098 
1099  /*
1100  * Write dirty SLRU pages to disk
1101  *
1102  * This is not actually necessary from a correctness point of view. We do
1103  * it merely as a debugging aid.
1104  *
1105  * We're doing this after the truncation to avoid writing pages right
1106  * before deleting the file in which they sit, which would be completely
1107  * pointless.
1108  */
1110 }
#define SerialPage(xid)
Definition: predicate.c:344
static SerialControl serialControl
Definition: predicate.c:355
static bool SerialPagePrecedesLogically(int64 page1, int64 page2)
Definition: predicate.c:732
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1199
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition: slru.c:1269
TransactionId tailXid
Definition: predicate.c:350

References SerialControlData::headPage, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), serialControl, SerialPage, SerialPagePrecedesLogically(), SerialSlruCtl, SimpleLruTruncate(), SimpleLruWriteAll(), SerialControlData::tailXid, and TransactionIdIsValid.

Referenced by CheckPointGuts().

◆ CheckTableForSerializableConflictIn()

void CheckTableForSerializableConflictIn ( Relation  relation)

Definition at line 4389 of file predicate.c.

4390 {
4391  HASH_SEQ_STATUS seqstat;
4392  PREDICATELOCKTARGET *target;
4393  Oid dbId;
4394  Oid heapId;
4395  int i;
4396 
4397  /*
4398  * Bail out quickly if there are no serializable transactions running.
4399  * It's safe to check this without taking locks because the caller is
4400  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4401  * would matter here can be acquired while that is held.
4402  */
4404  return;
4405 
4406  if (!SerializationNeededForWrite(relation))
4407  return;
4408 
4409  /*
4410  * We're doing a write which might cause rw-conflicts now or later.
4411  * Memorize that fact.
4412  */
4413  MyXactDidWrite = true;
4414 
4415  Assert(relation->rd_index == NULL); /* not an index relation */
4416 
4417  dbId = relation->rd_locator.dbOid;
4418  heapId = relation->rd_id;
4419 
4420  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
4421  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4423  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4424 
4425  /* Scan through target list */
4427 
4428  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4429  {
4430  dlist_mutable_iter iter;
4431 
4432  /*
4433  * Check whether this is a target which needs attention.
4434  */
4435  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4436  continue; /* wrong relation id */
4437  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4438  continue; /* wrong database id */
4439 
4440  /*
4441  * Loop through locks for this target and flag conflicts.
4442  */
4443  dlist_foreach_modify(iter, &target->predicateLocks)
4444  {
4445  PREDICATELOCK *predlock =
4446  dlist_container(PREDICATELOCK, targetLink, iter.cur);
4447 
4448  if (predlock->tag.myXact != MySerializableXact
4450  {
4452  }
4453  }
4454  }
4455 
4456  /* Release locks in reverse order */
4457  LWLockRelease(SerializableXactHashLock);
4458  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4460  LWLockRelease(SerializablePredicateListLock);
4461 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1431
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1421
#define dlist_foreach_modify(iter, lhead)
Definition: ilist.h:640
int i
Definition: isn.c:73
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:103
unsigned int Oid
Definition: postgres_ext.h:31
static PredXactList PredXact
Definition: predicate.c:385
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:262
static HTAB * PredicateLockTargetHash
Definition: predicate.c:398
SERIALIZABLEXACT * myXact
TransactionId SxactGlobalXmin
Form_pg_index rd_index
Definition: rel.h:191
dlist_node * cur
Definition: ilist.h:200

References Assert(), dlist_mutable_iter::cur, RelFileLocator::dbOid, dlist_container, dlist_foreach_modify, FlagRWConflict(), GET_PREDICATELOCKTARGETTAG_DB, GET_PREDICATELOCKTARGETTAG_RELATION, hash_seq_init(), hash_seq_search(), i, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myXact, MyXactDidWrite, NUM_PREDICATELOCK_PARTITIONS, PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredXact, RelationData::rd_id, RelationData::rd_index, RelationData::rd_locator, RWConflictExists(), SerializationNeededForWrite(), PredXactListData::SxactGlobalXmin, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, and TransactionIdIsValid.

Referenced by ExecuteTruncateGuts(), and heap_drop_with_catalog().

◆ CheckTargetForConflictsIn()

static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag)
static

Definition at line 4136 of file predicate.c.

4137 {
4138  uint32 targettaghash;
4139  LWLock *partitionLock;
4140  PREDICATELOCKTARGET *target;
4141  PREDICATELOCK *mypredlock = NULL;
4142  PREDICATELOCKTAG mypredlocktag;
4143  dlist_mutable_iter iter;
4144 
4146 
4147  /*
4148  * The same hash and LW lock apply to the lock target and the lock itself.
4149  */
4150  targettaghash = PredicateLockTargetTagHashCode(targettag);
4151  partitionLock = PredicateLockHashPartitionLock(targettaghash);
4152  LWLockAcquire(partitionLock, LW_SHARED);
4153  target = (PREDICATELOCKTARGET *)
4155  targettag, targettaghash,
4156  HASH_FIND, NULL);
4157  if (!target)
4158  {
4159  /* Nothing has this target locked; we're done here. */
4160  LWLockRelease(partitionLock);
4161  return;
4162  }
4163 
4164  /*
4165  * Each lock for an overlapping transaction represents a conflict: a
4166  * rw-dependency in to this transaction.
4167  */
4168  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4169 
4170  dlist_foreach_modify(iter, &target->predicateLocks)
4171  {
4172  PREDICATELOCK *predlock =
4173  dlist_container(PREDICATELOCK, targetLink, iter.cur);
4174  SERIALIZABLEXACT *sxact = predlock->tag.myXact;
4175 
4176  if (sxact == MySerializableXact)
4177  {
4178  /*
4179  * If we're getting a write lock on a tuple, we don't need a
4180  * predicate (SIREAD) lock on the same tuple. We can safely remove
4181  * our SIREAD lock, but we'll defer doing so until after the loop
4182  * because that requires upgrading to an exclusive partition lock.
4183  *
4184  * We can't use this optimization within a subtransaction because
4185  * the subtransaction could roll back, and we would be left
4186  * without any lock at the top level.
4187  */
4188  if (!IsSubTransaction()
4189  && GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
4190  {
4191  mypredlock = predlock;
4192  mypredlocktag = predlock->tag;
4193  }
4194  }
4195  else if (!SxactIsDoomed(sxact)
4196  && (!SxactIsCommitted(sxact)
4198  sxact->finishedBefore))
4200  {
4201  LWLockRelease(SerializableXactHashLock);
4202  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4203 
4204  /*
4205  * Re-check after getting exclusive lock because the other
4206  * transaction may have flagged a conflict.
4207  */
4208  if (!SxactIsDoomed(sxact)
4209  && (!SxactIsCommitted(sxact)
4211  sxact->finishedBefore))
4213  {
4215  }
4216 
4217  LWLockRelease(SerializableXactHashLock);
4218  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4219  }
4220  }
4221  LWLockRelease(SerializableXactHashLock);
4222  LWLockRelease(partitionLock);
4223 
4224  /*
4225  * If we found one of our own SIREAD locks to remove, remove it now.
4226  *
4227  * At this point our transaction already has a RowExclusiveLock on the
4228  * relation, so we are OK to drop the predicate lock on the tuple, if
4229  * found, without fearing that another write against the tuple will occur
4230  * before the MVCC information makes it to the buffer.
4231  */
4232  if (mypredlock != NULL)
4233  {
4234  uint32 predlockhashcode;
4235  PREDICATELOCK *rmpredlock;
4236 
4237  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4238  if (IsInParallelMode())
4240  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4241  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4242 
4243  /*
4244  * Remove the predicate lock from shared memory, if it wasn't removed
4245  * while the locks were released. One way that could happen is from
4246  * autovacuum cleaning up an index.
4247  */
4248  predlockhashcode = PredicateLockHashCodeFromTargetHashCode
4249  (&mypredlocktag, targettaghash);
4250  rmpredlock = (PREDICATELOCK *)
4252  &mypredlocktag,
4253  predlockhashcode,
4254  HASH_FIND, NULL);
4255  if (rmpredlock != NULL)
4256  {
4257  Assert(rmpredlock == mypredlock);
4258 
4259  dlist_delete(&(mypredlock->targetLink));
4260  dlist_delete(&(mypredlock->xactLink));
4261 
4262  rmpredlock = (PREDICATELOCK *)
4264  &mypredlocktag,
4265  predlockhashcode,
4266  HASH_REMOVE, NULL);
4267  Assert(rmpredlock == mypredlock);
4268 
4269  RemoveTargetIfNoLongerUsed(target, targettaghash);
4270  }
4271 
4272  LWLockRelease(SerializableXactHashLock);
4273  LWLockRelease(partitionLock);
4274  if (IsInParallelMode())
4276  LWLockRelease(SerializablePredicateListLock);
4277 
4278  if (rmpredlock != NULL)
4279  {
4280  /*
4281  * Remove entry in local lock table if it exists. It's OK if it
4282  * doesn't exist; that means the lock was transferred to a new
4283  * target by a different backend.
4284  */
4286  targettag, targettaghash,
4287  HASH_REMOVE, NULL);
4288 
4289  DecrementParentLocks(targettag);
4290  }
4291  }
4292 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:966
@ HASH_REMOVE
Definition: hsearch.h:115
static void dlist_delete(dlist_node *node)
Definition: ilist.h:405
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2361
static HTAB * PredicateLockHash
Definition: predicate.c:399
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:304
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2153
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:317
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:259
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:223
Definition: lwlock.h:41
TransactionId finishedBefore
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
bool IsSubTransaction(void)
Definition: xact.c:4905
bool IsInParallelMode(void)
Definition: xact.c:1069

References Assert(), dlist_mutable_iter::cur, DecrementParentLocks(), dlist_container, dlist_delete(), dlist_foreach_modify, SERIALIZABLEXACT::finishedBefore, FlagRWConflict(), GET_PREDICATELOCKTARGETTAG_OFFSET, GetTransactionSnapshot(), HASH_FIND, HASH_REMOVE, hash_search_with_hash_value(), InvalidSerializableXact, IsInParallelMode(), IsSubTransaction(), LocalPredicateLockHash, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myXact, SERIALIZABLEXACT::perXactPredicateListLock, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredicateLockTargetTagHashCode, RemoveTargetIfNoLongerUsed(), RWConflictExists(), SxactIsCommitted, SxactIsDoomed, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdPrecedes(), and PREDICATELOCK::xactLink.

Referenced by CheckForSerializableConflictIn().

◆ ClearOldPredicateLocks()

static void ClearOldPredicateLocks ( void  )
static

Definition at line 3667 of file predicate.c.

3668 {
3669  dlist_mutable_iter iter;
3670 
3671  /*
3672  * Loop through finished transactions. They are in commit order, so we can
3673  * stop as soon as we find one that's still interesting.
3674  */
3675  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3676  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3678  {
3679  SERIALIZABLEXACT *finishedSxact =
3680  dlist_container(SERIALIZABLEXACT, finishedLink, iter.cur);
3681 
3685  {
3686  /*
3687  * This transaction committed before any in-progress transaction
3688  * took its snapshot. It's no longer interesting.
3689  */
3690  LWLockRelease(SerializableXactHashLock);
3691  dlist_delete_thoroughly(&finishedSxact->finishedLink);
3692  ReleaseOneSerializableXact(finishedSxact, false, false);
3693  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3694  }
3695  else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3696  && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3697  {
3698  /*
3699  * Any active transactions that took their snapshot before this
3700  * transaction committed are read-only, so we can clear part of
3701  * its state.
3702  */
3703  LWLockRelease(SerializableXactHashLock);
3704 
3705  if (SxactIsReadOnly(finishedSxact))
3706  {
3707  /* A read-only transaction can be removed entirely */
3708  dlist_delete_thoroughly(&(finishedSxact->finishedLink));
3709  ReleaseOneSerializableXact(finishedSxact, false, false);
3710  }
3711  else
3712  {
3713  /*
3714  * A read-write transaction can only be partially cleared. We
3715  * need to keep the SERIALIZABLEXACT but can release the
3716  * SIREAD locks and conflicts in.
3717  */
3718  ReleaseOneSerializableXact(finishedSxact, true, false);
3719  }
3720 
3722  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3723  }
3724  else
3725  {
3726  /* Still interesting. */
3727  break;
3728  }
3729  }
3730  LWLockRelease(SerializableXactHashLock);
3731 
3732  /*
3733  * Loop through predicate locks on dummy transaction for summarized data.
3734  */
3735  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
3737  {
3738  PREDICATELOCK *predlock =
3739  dlist_container(PREDICATELOCK, xactLink, iter.cur);
3740  bool canDoPartialCleanup;
3741 
3742  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3743  Assert(predlock->commitSeqNo != 0);
3745  canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
3746  LWLockRelease(SerializableXactHashLock);
3747 
3748  /*
3749  * If this lock originally belonged to an old enough transaction, we
3750  * can release it.
3751  */
3752  if (canDoPartialCleanup)
3753  {
3754  PREDICATELOCKTAG tag;
3755  PREDICATELOCKTARGET *target;
3756  PREDICATELOCKTARGETTAG targettag;
3757  uint32 targettaghash;
3758  LWLock *partitionLock;
3759 
3760  tag = predlock->tag;
3761  target = tag.myTarget;
3762  targettag = target->tag;
3763  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3764  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3765 
3766  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3767 
3768  dlist_delete(&(predlock->targetLink));
3769  dlist_delete(&(predlock->xactLink));
3770 
3773  targettaghash),
3774  HASH_REMOVE, NULL);
3775  RemoveTargetIfNoLongerUsed(target, targettaghash);
3776 
3777  LWLockRelease(partitionLock);
3778  }
3779  }
3780 
3781  LWLockRelease(SerializablePredicateListLock);
3782  LWLockRelease(SerializableFinishedListLock);
3783 }
static void dlist_delete_thoroughly(dlist_node *node)
Definition: ilist.h:416
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:363
static dlist_head * FinishedSerializableTransactions
Definition: predicate.c:400
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize)
Definition: predicate.c:3805
SerCommitSeqNo commitSeqNo
SerCommitSeqNo CanPartialClearThrough
SerCommitSeqNo HavePartialClearedThrough
SerCommitSeqNo commitSeqNo
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:299

References Assert(), PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, PREDICATELOCK::commitSeqNo, dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_delete_thoroughly(), dlist_foreach_modify, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, HASH_REMOVE, hash_search_with_hash_value(), PredXactListData::HavePartialClearedThrough, InvalidSerCommitSeqNo, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, OldCommittedSxact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, PredXact, ReleaseOneSerializableXact(), RemoveTargetIfNoLongerUsed(), PredXactListData::SxactGlobalXmin, SxactIsReadOnly, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdIsValid, TransactionIdPrecedesOrEquals(), and PREDICATELOCK::xactLink.

Referenced by ReleasePredicateLocks().

◆ CoarserLockCovers()

static bool CoarserLockCovers ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2081 of file predicate.c.

2082 {
2083  PREDICATELOCKTARGETTAG targettag,
2084  parenttag;
2085 
2086  targettag = *newtargettag;
2087 
2088  /* check parents iteratively until no more */
2089  while (GetParentPredicateLockTag(&targettag, &parenttag))
2090  {
2091  targettag = parenttag;
2092  if (PredicateLockExists(&targettag))
2093  return true;
2094  }
2095 
2096  /* no more parents to check; lock is not covered */
2097  return false;
2098 }
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2015

References GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

◆ CreateLocalPredicateLockHash()

static void CreateLocalPredicateLockHash ( void  )
static

Definition at line 1910 of file predicate.c.

1911 {
1912  HASHCTL hash_ctl;
1913 
1914  /* Initialize the backend-local hash table of parent locks */
1915  Assert(LocalPredicateLockHash == NULL);
1916  hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1917  hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1918  LocalPredicateLockHash = hash_create("Local predicate lock",
1920  &hash_ctl,
1921  HASH_ELEM | HASH_BLOBS);
1922 }
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
int max_predicate_locks_per_xact
Definition: predicate.c:372
struct LOCALPREDICATELOCK LOCALPREDICATELOCK
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76

References Assert(), HASHCTL::entrysize, HASH_BLOBS, hash_create(), HASH_ELEM, HASHCTL::keysize, LocalPredicateLockHash, and max_predicate_locks_per_xact.

Referenced by AttachSerializableXact(), and GetSerializableTransactionSnapshotInt().

◆ CreatePredicateLock()

static void CreatePredicateLock ( const PREDICATELOCKTARGETTAG targettag,
uint32  targettaghash,
SERIALIZABLEXACT sxact 
)
static

Definition at line 2423 of file predicate.c.

2426 {
2427  PREDICATELOCKTARGET *target;
2428  PREDICATELOCKTAG locktag;
2429  PREDICATELOCK *lock;
2430  LWLock *partitionLock;
2431  bool found;
2432 
2433  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2434 
2435  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2436  if (IsInParallelMode())
2438  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2439 
2440  /* Make sure that the target is represented. */
2441  target = (PREDICATELOCKTARGET *)
2443  targettag, targettaghash,
2444  HASH_ENTER_NULL, &found);
2445  if (!target)
2446  ereport(ERROR,
2447  (errcode(ERRCODE_OUT_OF_MEMORY),
2448  errmsg("out of shared memory"),
2449  errhint("You might need to increase %s.", "max_pred_locks_per_transaction")));
2450  if (!found)
2451  dlist_init(&target->predicateLocks);
2452 
2453  /* We've got the sxact and target, make sure they're joined. */
2454  locktag.myTarget = target;
2455  locktag.myXact = sxact;
2456  lock = (PREDICATELOCK *)
2458  PredicateLockHashCodeFromTargetHashCode(&locktag, targettaghash),
2459  HASH_ENTER_NULL, &found);
2460  if (!lock)
2461  ereport(ERROR,
2462  (errcode(ERRCODE_OUT_OF_MEMORY),
2463  errmsg("out of shared memory"),
2464  errhint("You might need to increase %s.", "max_pred_locks_per_transaction")));
2465 
2466  if (!found)
2467  {
2468  dlist_push_tail(&target->predicateLocks, &lock->targetLink);
2469  dlist_push_tail(&sxact->predicateLocks, &lock->xactLink);
2471  }
2472 
2473  LWLockRelease(partitionLock);
2474  if (IsInParallelMode())
2476  LWLockRelease(SerializablePredicateListLock);
2477 }
@ HASH_ENTER_NULL
Definition: hsearch.h:116
static void dlist_init(dlist_head *head)
Definition: ilist.h:314
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364

References PREDICATELOCK::commitSeqNo, dlist_init(), dlist_push_tail(), ereport, errcode(), errhint(), errmsg(), ERROR, HASH_ENTER_NULL, hash_search_with_hash_value(), InvalidSerCommitSeqNo, IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, SERIALIZABLEXACT::perXactPredicateListLock, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by predicatelock_twophase_recover(), and PredicateLockAcquire().

◆ CreatePredXact()

static SERIALIZABLEXACT * CreatePredXact ( void  )
static

Definition at line 583 of file predicate.c.

584 {
585  SERIALIZABLEXACT *sxact;
586 
588  return NULL;
589 
590  sxact = dlist_container(SERIALIZABLEXACT, xactLink,
593  return sxact;
594 }
static dlist_node * dlist_pop_head_node(dlist_head *head)
Definition: ilist.h:450

References PredXactListData::activeList, PredXactListData::availableList, dlist_container, dlist_is_empty(), dlist_pop_head_node(), dlist_push_tail(), PredXact, and SERIALIZABLEXACT::xactLink.

Referenced by GetSerializableTransactionSnapshotInt(), InitPredicateLocks(), and predicatelock_twophase_recover().

◆ DecrementParentLocks()

static void DecrementParentLocks ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2361 of file predicate.c.

2362 {
2363  PREDICATELOCKTARGETTAG parenttag,
2364  nexttag;
2365 
2366  parenttag = *targettag;
2367 
2368  while (GetParentPredicateLockTag(&parenttag, &nexttag))
2369  {
2370  uint32 targettaghash;
2371  LOCALPREDICATELOCK *parentlock,
2372  *rmlock PG_USED_FOR_ASSERTS_ONLY;
2373 
2374  parenttag = nexttag;
2375  targettaghash = PredicateLockTargetTagHashCode(&parenttag);
2376  parentlock = (LOCALPREDICATELOCK *)
2378  &parenttag, targettaghash,
2379  HASH_FIND, NULL);
2380 
2381  /*
2382  * There's a small chance the parent lock doesn't exist in the lock
2383  * table. This can happen if we prematurely removed it because an
2384  * index split caused the child refcount to be off.
2385  */
2386  if (parentlock == NULL)
2387  continue;
2388 
2389  parentlock->childLocks--;
2390 
2391  /*
2392  * Under similar circumstances the parent lock's refcount might be
2393  * zero. This only happens if we're holding that lock (otherwise we
2394  * would have removed the entry).
2395  */
2396  if (parentlock->childLocks < 0)
2397  {
2398  Assert(parentlock->held);
2399  parentlock->childLocks = 0;
2400  }
2401 
2402  if ((parentlock->childLocks == 0) && (!parentlock->held))
2403  {
2404  rmlock = (LOCALPREDICATELOCK *)
2406  &parenttag, targettaghash,
2407  HASH_REMOVE, NULL);
2408  Assert(rmlock == parentlock);
2409  }
2410  }
2411 }
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:171

References Assert(), LOCALPREDICATELOCK::childLocks, GetParentPredicateLockTag(), HASH_FIND, HASH_REMOVE, hash_search_with_hash_value(), LOCALPREDICATELOCK::held, LocalPredicateLockHash, PG_USED_FOR_ASSERTS_ONLY, and PredicateLockTargetTagHashCode.

Referenced by CheckTargetForConflictsIn(), and DeleteChildTargetLocks().

◆ DeleteChildTargetLocks()

static void DeleteChildTargetLocks ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2184 of file predicate.c.

2185 {
2186  SERIALIZABLEXACT *sxact;
2187  PREDICATELOCK *predlock;
2188  dlist_mutable_iter iter;
2189 
2190  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2191  sxact = MySerializableXact;
2192  if (IsInParallelMode())
2194 
2195  dlist_foreach_modify(iter, &sxact->predicateLocks)
2196  {
2197  PREDICATELOCKTAG oldlocktag;
2198  PREDICATELOCKTARGET *oldtarget;
2199  PREDICATELOCKTARGETTAG oldtargettag;
2200 
2201  predlock = dlist_container(PREDICATELOCK, xactLink, iter.cur);
2202 
2203  oldlocktag = predlock->tag;
2204  Assert(oldlocktag.myXact == sxact);
2205  oldtarget = oldlocktag.myTarget;
2206  oldtargettag = oldtarget->tag;
2207 
2208  if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
2209  {
2210  uint32 oldtargettaghash;
2211  LWLock *partitionLock;
2213 
2214  oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2215  partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2216 
2217  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2218 
2219  dlist_delete(&predlock->xactLink);
2220  dlist_delete(&predlock->targetLink);
2221  rmpredlock = hash_search_with_hash_value
2223  &oldlocktag,
2225  oldtargettaghash),
2226  HASH_REMOVE, NULL);
2227  Assert(rmpredlock == predlock);
2228 
2229  RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2230 
2231  LWLockRelease(partitionLock);
2232 
2233  DecrementParentLocks(&oldtargettag);
2234  }
2235  }
2236  if (IsInParallelMode())
2238  LWLockRelease(SerializablePredicateListLock);
2239 }
#define TargetTagIsCoveredBy(covered_target, covering_target)
Definition: predicate.c:234

References Assert(), dlist_mutable_iter::cur, DecrementParentLocks(), dlist_container, dlist_delete(), dlist_foreach_modify, HASH_REMOVE, hash_search_with_hash_value(), IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, SERIALIZABLEXACT::perXactPredicateListLock, PG_USED_FOR_ASSERTS_ONLY, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, RemoveTargetIfNoLongerUsed(), PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TargetTagIsCoveredBy, and PREDICATELOCK::xactLink.

Referenced by PredicateLockAcquire().

◆ DeleteLockTarget()

static void DeleteLockTarget ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

Definition at line 2639 of file predicate.c.

2640 {
2641  dlist_mutable_iter iter;
2642 
2643  Assert(LWLockHeldByMeInMode(SerializablePredicateListLock,
2644  LW_EXCLUSIVE));
2646 
2647  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2648 
2649  dlist_foreach_modify(iter, &target->predicateLocks)
2650  {
2651  PREDICATELOCK *predlock =
2652  dlist_container(PREDICATELOCK, targetLink, iter.cur);
2653  bool found;
2654 
2655  dlist_delete(&(predlock->xactLink));
2656  dlist_delete(&(predlock->targetLink));
2657 
2660  &predlock->tag,
2662  targettaghash),
2663  HASH_REMOVE, &found);
2664  Assert(found);
2665  }
2666  LWLockRelease(SerializableXactHashLock);
2667 
2668  /* Remove the target itself, if possible. */
2669  RemoveTargetIfNoLongerUsed(target, targettaghash);
2670 }
bool LWLockHeldByMe(LWLock *lock)
Definition: lwlock.c:1893
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1937

References Assert(), dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_foreach_modify, HASH_REMOVE, hash_search_with_hash_value(), LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMe(), LWLockHeldByMeInMode(), LWLockRelease(), PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PREDICATELOCKTARGET::predicateLocks, RemoveTargetIfNoLongerUsed(), PREDICATELOCK::tag, PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by TransferPredicateLocksToNewTarget().

◆ DropAllPredicateLocksFromTable()

static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
)
static

Definition at line 2907 of file predicate.c.

2908 {
2909  HASH_SEQ_STATUS seqstat;
2910  PREDICATELOCKTARGET *oldtarget;
2911  PREDICATELOCKTARGET *heaptarget;
2912  Oid dbId;
2913  Oid relId;
2914  Oid heapId;
2915  int i;
2916  bool isIndex;
2917  bool found;
2918  uint32 heaptargettaghash;
2919 
2920  /*
2921  * Bail out quickly if there are no serializable transactions running.
2922  * It's safe to check this without taking locks because the caller is
2923  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
2924  * would matter here can be acquired while that is held.
2925  */
2927  return;
2928 
2929  if (!PredicateLockingNeededForRelation(relation))
2930  return;
2931 
2932  dbId = relation->rd_locator.dbOid;
2933  relId = relation->rd_id;
2934  if (relation->rd_index == NULL)
2935  {
2936  isIndex = false;
2937  heapId = relId;
2938  }
2939  else
2940  {
2941  isIndex = true;
2942  heapId = relation->rd_index->indrelid;
2943  }
2944  Assert(heapId != InvalidOid);
2945  Assert(transfer || !isIndex); /* index OID only makes sense with
2946  * transfer */
2947 
2948  /* Retrieve first time needed, then keep. */
2949  heaptargettaghash = 0;
2950  heaptarget = NULL;
2951 
2952  /* Acquire locks on all lock partitions */
2953  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
2954  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
2956  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2957 
2958  /*
2959  * Remove the dummy entry to give us scratch space, so we know we'll be
2960  * able to create the new lock target.
2961  */
2962  if (transfer)
2963  RemoveScratchTarget(true);
2964 
2965  /* Scan through target map */
2967 
2968  while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
2969  {
2970  dlist_mutable_iter iter;
2971 
2972  /*
2973  * Check whether this is a target which needs attention.
2974  */
2975  if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) != relId)
2976  continue; /* wrong relation id */
2977  if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
2978  continue; /* wrong database id */
2979  if (transfer && !isIndex
2981  continue; /* already the right lock */
2982 
2983  /*
2984  * If we made it here, we have work to do. We make sure the heap
2985  * relation lock exists, then we walk the list of predicate locks for
2986  * the old target we found, moving all locks to the heap relation lock
2987  * -- unless they already hold that.
2988  */
2989 
2990  /*
2991  * First make sure we have the heap relation target. We only need to
2992  * do this once.
2993  */
2994  if (transfer && heaptarget == NULL)
2995  {
2996  PREDICATELOCKTARGETTAG heaptargettag;
2997 
2998  SET_PREDICATELOCKTARGETTAG_RELATION(heaptargettag, dbId, heapId);
2999  heaptargettaghash = PredicateLockTargetTagHashCode(&heaptargettag);
3001  &heaptargettag,
3002  heaptargettaghash,
3003  HASH_ENTER, &found);
3004  if (!found)
3005  dlist_init(&heaptarget->predicateLocks);
3006  }
3007 
3008  /*
3009  * Loop through all the locks on the old target, replacing them with
3010  * locks on the new target.
3011  */
3012  dlist_foreach_modify(iter, &oldtarget->predicateLocks)
3013  {
3014  PREDICATELOCK *oldpredlock =
3015  dlist_container(PREDICATELOCK, targetLink, iter.cur);
3016  PREDICATELOCK *newpredlock;
3017  SerCommitSeqNo oldCommitSeqNo;
3018  SERIALIZABLEXACT *oldXact;
3019 
3020  /*
3021  * Remove the old lock first. This avoids the chance of running
3022  * out of lock structure entries for the hash table.
3023  */
3024  oldCommitSeqNo = oldpredlock->commitSeqNo;
3025  oldXact = oldpredlock->tag.myXact;
3026 
3027  dlist_delete(&(oldpredlock->xactLink));
3028 
3029  /*
3030  * No need for retail delete from oldtarget list, we're removing
3031  * the whole target anyway.
3032  */
3034  &oldpredlock->tag,
3035  HASH_REMOVE, &found);
3036  Assert(found);
3037 
3038  if (transfer)
3039  {
3040  PREDICATELOCKTAG newpredlocktag;
3041 
3042  newpredlocktag.myTarget = heaptarget;
3043  newpredlocktag.myXact = oldXact;
3044  newpredlock = (PREDICATELOCK *)
3046  &newpredlocktag,
3048  heaptargettaghash),
3049  HASH_ENTER,
3050  &found);
3051  if (!found)
3052  {
3053  dlist_push_tail(&(heaptarget->predicateLocks),
3054  &(newpredlock->targetLink));
3055  dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
3056  &(newpredlock->xactLink));
3057  newpredlock->commitSeqNo = oldCommitSeqNo;
3058  }
3059  else
3060  {
3061  if (newpredlock->commitSeqNo < oldCommitSeqNo)
3062  newpredlock->commitSeqNo = oldCommitSeqNo;
3063  }
3064 
3065  Assert(newpredlock->commitSeqNo != 0);
3066  Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
3067  || (newpredlock->tag.myXact == OldCommittedSxact));
3068  }
3069  }
3070 
3072  &found);
3073  Assert(found);
3074  }
3075 
3076  /* Put the scratch entry back */
3077  if (transfer)
3078  RestoreScratchTarget(true);
3079 
3080  /* Release locks in reverse order */
3081  LWLockRelease(SerializableXactHashLock);
3082  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3084  LWLockRelease(SerializablePredicateListLock);
3085 }
#define InvalidOid
Definition: postgres_ext.h:36
static bool PredicateLockingNeededForRelation(Relation relation)
Definition: predicate.c:499
static void RestoreScratchTarget(bool lockheld)
Definition: predicate.c:2131
static void RemoveScratchTarget(bool lockheld)
Definition: predicate.c:2110
@ PREDLOCKTAG_RELATION
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)

References Assert(), PREDICATELOCK::commitSeqNo, dlist_mutable_iter::cur, RelFileLocator::dbOid, dlist_container, dlist_delete(), dlist_foreach_modify, dlist_init(), dlist_push_tail(), GET_PREDICATELOCKTARGETTAG_DB, GET_PREDICATELOCKTARGETTAG_RELATION, GET_PREDICATELOCKTARGETTAG_TYPE, HASH_ENTER, HASH_REMOVE, hash_search(), hash_search_with_hash_value(), hash_seq_init(), hash_seq_search(), i, InvalidOid, InvalidSerCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, NUM_PREDICATELOCK_PARTITIONS, OldCommittedSxact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLockByIndex, PredicateLockingNeededForRelation(), SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredicateLockTargetTagHashCode, PREDLOCKTAG_RELATION, PredXact, RelationData::rd_id, RelationData::rd_index, RelationData::rd_locator, RemoveScratchTarget(), RestoreScratchTarget(), SET_PREDICATELOCKTARGETTAG_RELATION, PredXactListData::SxactGlobalXmin, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdIsValid, and PREDICATELOCK::xactLink.

Referenced by TransferPredicateLocksToHeapRelation().

◆ FlagRWConflict()

static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4471 of file predicate.c.

4472 {
4473  Assert(reader != writer);
4474 
4475  /* First, see if this conflict causes failure. */
4477 
4478  /* Actually do the conflict flagging. */
4479  if (reader == OldCommittedSxact)
4481  else if (writer == OldCommittedSxact)
4483  else
4484  SetRWConflict(reader, writer);
4485 }
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:644
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4506
#define SXACT_FLAG_SUMMARY_CONFLICT_IN

References Assert(), SERIALIZABLEXACT::flags, OldCommittedSxact, OnConflict_CheckForSerializationFailure(), SetRWConflict(), SXACT_FLAG_SUMMARY_CONFLICT_IN, and SXACT_FLAG_SUMMARY_CONFLICT_OUT.

Referenced by CheckForSerializableConflictOut(), CheckTableForSerializableConflictIn(), and CheckTargetForConflictsIn().

◆ FlagSxactUnsafe()

static void FlagSxactUnsafe ( SERIALIZABLEXACT sxact)
static

Definition at line 700 of file predicate.c.

701 {
702  dlist_mutable_iter iter;
703 
704  Assert(SxactIsReadOnly(sxact));
705  Assert(!SxactIsROSafe(sxact));
706 
707  sxact->flags |= SXACT_FLAG_RO_UNSAFE;
708 
709  /*
710  * We know this isn't a safe snapshot, so we can stop looking for other
711  * potential conflicts.
712  */
714  {
715  RWConflict conflict =
716  dlist_container(RWConflictData, inLink, iter.cur);
717 
718  Assert(!SxactIsReadOnly(conflict->sxactOut));
719  Assert(sxact == conflict->sxactIn);
720 
721  ReleaseRWConflict(conflict);
722  }
723 }
#define SxactIsROSafe(sxact)
Definition: predicate.c:292
static void ReleaseRWConflict(RWConflict conflict)
Definition: predicate.c:692
#define SXACT_FLAG_RO_UNSAFE
SERIALIZABLEXACT * sxactIn
SERIALIZABLEXACT * sxactOut
dlist_head possibleUnsafeConflicts

References Assert(), dlist_mutable_iter::cur, dlist_container, dlist_foreach_modify, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::possibleUnsafeConflicts, ReleaseRWConflict(), SXACT_FLAG_RO_UNSAFE, RWConflictData::sxactIn, SxactIsReadOnly, SxactIsROSafe, and RWConflictData::sxactOut.

Referenced by ReleasePredicateLocks().

◆ GetParentPredicateLockTag()

static bool GetParentPredicateLockTag ( const PREDICATELOCKTARGETTAG tag,
PREDICATELOCKTARGETTAG parent 
)
static

Definition at line 2042 of file predicate.c.

2044 {
2045  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2046  {
2047  case PREDLOCKTAG_RELATION:
2048  /* relation locks have no parent lock */
2049  return false;
2050 
2051  case PREDLOCKTAG_PAGE:
2052  /* parent lock is relation lock */
2056 
2057  return true;
2058 
2059  case PREDLOCKTAG_TUPLE:
2060  /* parent lock is page lock */
2065  return true;
2066  }
2067 
2068  /* not reachable */
2069  Assert(false);
2070  return false;
2071 }
@ PREDLOCKTAG_PAGE
@ PREDLOCKTAG_TUPLE

References Assert(), GET_PREDICATELOCKTARGETTAG_DB, GET_PREDICATELOCKTARGETTAG_PAGE, GET_PREDICATELOCKTARGETTAG_RELATION, GET_PREDICATELOCKTARGETTAG_TYPE, PREDLOCKTAG_PAGE, PREDLOCKTAG_RELATION, PREDLOCKTAG_TUPLE, SET_PREDICATELOCKTARGETTAG_PAGE, and SET_PREDICATELOCKTARGETTAG_RELATION.

Referenced by CheckAndPromotePredicateLockRequest(), CoarserLockCovers(), DecrementParentLocks(), and PredicateLockPageSplit().

◆ GetPredicateLockStatusData()

PredicateLockData* GetPredicateLockStatusData ( void  )

Definition at line 1415 of file predicate.c.

1416 {
1418  int i;
1419  int els,
1420  el;
1421  HASH_SEQ_STATUS seqstat;
1422  PREDICATELOCK *predlock;
1423 
1425 
1426  /*
1427  * To ensure consistency, take simultaneous locks on all partition locks
1428  * in ascending order, then SerializableXactHashLock.
1429  */
1430  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
1432  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1433 
1434  /* Get number of locks and allocate appropriately-sized arrays. */
1436  data->nelements = els;
1437  data->locktags = (PREDICATELOCKTARGETTAG *)
1438  palloc(sizeof(PREDICATELOCKTARGETTAG) * els);
1439  data->xacts = (SERIALIZABLEXACT *)
1440  palloc(sizeof(SERIALIZABLEXACT) * els);
1441 
1442 
1443  /* Scan through PredicateLockHash and copy contents */
1444  hash_seq_init(&seqstat, PredicateLockHash);
1445 
1446  el = 0;
1447 
1448  while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
1449  {
1450  data->locktags[el] = predlock->tag.myTarget->tag;
1451  data->xacts[el] = *predlock->tag.myXact;
1452  el++;
1453  }
1454 
1455  Assert(el == els);
1456 
1457  /* Release locks in reverse order */
1458  LWLockRelease(SerializableXactHashLock);
1459  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1461 
1462  return data;
1463 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1377
void * palloc(Size size)
Definition: mcxt.c:1201
const void * data

References Assert(), data, hash_get_num_entries(), hash_seq_init(), hash_seq_search(), i, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, NUM_PREDICATELOCK_PARTITIONS, palloc(), PredicateLockHash, PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::tag, and PREDICATELOCK::tag.

Referenced by pg_lock_status().

◆ GetSafeSnapshot()

static Snapshot GetSafeSnapshot ( Snapshot  origSnapshot)
static

Definition at line 1528 of file predicate.c.

1529 {
1530  Snapshot snapshot;
1531 
1533 
1534  while (true)
1535  {
1536  /*
1537  * GetSerializableTransactionSnapshotInt is going to call
1538  * GetSnapshotData, so we need to provide it the static snapshot area
1539  * our caller passed to us. The pointer returned is actually the same
1540  * one passed to it, but we avoid assuming that here.
1541  */
1542  snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
1543  NULL, InvalidPid);
1544 
1546  return snapshot; /* no concurrent r/w xacts; it's safe */
1547 
1548  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1549 
1550  /*
1551  * Wait for concurrent transactions to finish. Stop early if one of
1552  * them marked us as conflicted.
1553  */
1557  {
1558  LWLockRelease(SerializableXactHashLock);
1559  ProcWaitForSignal(WAIT_EVENT_SAFE_SNAPSHOT);
1560  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1561  }
1563 
1565  {
1566  LWLockRelease(SerializableXactHashLock);
1567  break; /* success */
1568  }
1569 
1570  LWLockRelease(SerializableXactHashLock);
1571 
1572  /* else, need to retry... */
1573  ereport(DEBUG2,
1575  errmsg_internal("deferrable snapshot was unsafe; trying a new one")));
1576  ReleasePredicateLocks(false, false);
1577  }
1578 
1579  /*
1580  * Now we have a safe snapshot, so we don't need to do any further checks.
1581  */
1583  ReleasePredicateLocks(false, true);
1584 
1585  return snapshot;
1586 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1162
#define DEBUG2
Definition: elog.h:29
#define InvalidPid
Definition: miscadmin.h:32
#define SxactIsROUnsafe(sxact)
Definition: predicate.c:293
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1734
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3282
#define SXACT_FLAG_DEFERRABLE_WAITING
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1847
bool XactDeferrable
Definition: xact.c:85
bool XactReadOnly
Definition: xact.c:82

References Assert(), DEBUG2, dlist_is_empty(), ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errmsg_internal(), SERIALIZABLEXACT::flags, GetSerializableTransactionSnapshotInt(), InvalidPid, InvalidSerializableXact, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXACT::possibleUnsafeConflicts, ProcWaitForSignal(), ReleasePredicateLocks(), SXACT_FLAG_DEFERRABLE_WAITING, SxactIsROSafe, SxactIsROUnsafe, XactDeferrable, and XactReadOnly.

Referenced by GetSerializableTransactionSnapshot().

◆ GetSafeSnapshotBlockingPids()

int GetSafeSnapshotBlockingPids ( int  blocked_pid,
int *  output,
int  output_size 
)

Definition at line 1598 of file predicate.c.

1599 {
1600  int num_written = 0;
1601  dlist_iter iter;
1602  SERIALIZABLEXACT *blocking_sxact = NULL;
1603 
1604  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1605 
1606  /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
1608  {
1609  SERIALIZABLEXACT *sxact =
1610  dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
1611 
1612  if (sxact->pid == blocked_pid)
1613  {
1614  blocking_sxact = sxact;
1615  break;
1616  }
1617  }
1618 
1619  /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
1620  if (blocking_sxact != NULL && SxactIsDeferrableWaiting(blocking_sxact))
1621  {
1622  /* Traverse the list of possible unsafe conflicts collecting PIDs. */
1623  dlist_foreach(iter, &blocking_sxact->possibleUnsafeConflicts)
1624  {
1625  RWConflict possibleUnsafeConflict =
1626  dlist_container(RWConflictData, inLink, iter.cur);
1627 
1628  output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
1629 
1630  if (num_written >= output_size)
1631  break;
1632  }
1633  }
1634 
1635  LWLockRelease(SerializableXactHashLock);
1636 
1637  return num_written;
1638 }
FILE * output
#define SxactIsDeferrableWaiting(sxact)
Definition: predicate.c:291

References PredXactListData::activeList, dlist_iter::cur, dlist_container, dlist_foreach, LW_SHARED, LWLockAcquire(), LWLockRelease(), output, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, PredXact, SxactIsDeferrableWaiting, and RWConflictData::sxactOut.

Referenced by pg_isolation_test_session_is_blocked(), and pg_safe_snapshot_blocking_pids().

◆ GetSerializableTransactionSnapshot()

Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot)

Definition at line 1652 of file predicate.c.

1653 {
1655 
1656  /*
1657  * Can't use serializable mode while recovery is still active, as it is,
1658  * for example, on a hot standby. We could get here despite the check in
1659  * check_transaction_isolation() if default_transaction_isolation is set
1660  * to serializable, so phrase the hint accordingly.
1661  */
1662  if (RecoveryInProgress())
1663  ereport(ERROR,
1664  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1665  errmsg("cannot use serializable mode in a hot standby"),
1666  errdetail("default_transaction_isolation is set to \"serializable\"."),
1667  errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1668 
1669  /*
1670  * A special optimization is available for SERIALIZABLE READ ONLY
1671  * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1672  * thereby avoid all SSI overhead once it's running.
1673  */
1675  return GetSafeSnapshot(snapshot);
1676 
1677  return GetSerializableTransactionSnapshotInt(snapshot,
1678  NULL, InvalidPid);
1679 }
int errdetail(const char *fmt,...)
Definition: elog.c:1208
static Snapshot GetSafeSnapshot(Snapshot origSnapshot)
Definition: predicate.c:1528
#define IsolationIsSerializable()
Definition: xact.h:52
bool RecoveryInProgress(void)
Definition: xlog.c:6211

References Assert(), ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, GetSafeSnapshot(), GetSerializableTransactionSnapshotInt(), InvalidPid, IsolationIsSerializable, RecoveryInProgress(), XactDeferrable, and XactReadOnly.

Referenced by GetTransactionSnapshot().

◆ GetSerializableTransactionSnapshotInt()

static Snapshot GetSerializableTransactionSnapshotInt ( Snapshot  snapshot,
VirtualTransactionId sourcevxid,
int  sourcepid 
)
static

Definition at line 1734 of file predicate.c.

1737 {
1738  PGPROC *proc;
1739  VirtualTransactionId vxid;
1740  SERIALIZABLEXACT *sxact,
1741  *othersxact;
1742 
1743  /* We only do this for serializable transactions. Once. */
1745 
1747 
1748  /*
1749  * Since all parts of a serializable transaction must use the same
1750  * snapshot, it is too late to establish one after a parallel operation
1751  * has begun.
1752  */
1753  if (IsInParallelMode())
1754  elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
1755 
1756  proc = MyProc;
1757  Assert(proc != NULL);
1758  GET_VXID_FROM_PGPROC(vxid, *proc);
1759 
1760  /*
1761  * First we get the sxact structure, which may involve looping and access
1762  * to the "finished" list to free a structure for use.
1763  *
1764  * We must hold SerializableXactHashLock when taking/checking the snapshot
1765  * to avoid race conditions, for much the same reasons that
1766  * GetSnapshotData takes the ProcArrayLock. Since we might have to
1767  * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
1768  * this means we have to create the sxact first, which is a bit annoying
1769  * (in particular, an elog(ERROR) in procarray.c would cause us to leak
1770  * the sxact). Consider refactoring to avoid this.
1771  */
1772 #ifdef TEST_SUMMARIZE_SERIAL
1774 #endif
1775  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1776  do
1777  {
1778  sxact = CreatePredXact();
1779  /* If null, push out committed sxact to SLRU summary & retry. */
1780  if (!sxact)
1781  {
1782  LWLockRelease(SerializableXactHashLock);
1784  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1785  }
1786  } while (!sxact);
1787 
1788  /* Get the snapshot, or check that it's safe to use */
1789  if (!sourcevxid)
1790  snapshot = GetSnapshotData(snapshot);
1791  else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid))
1792  {
1793  ReleasePredXact(sxact);
1794  LWLockRelease(SerializableXactHashLock);
1795  ereport(ERROR,
1796  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1797  errmsg("could not import the requested snapshot"),
1798  errdetail("The source process with PID %d is not running anymore.",
1799  sourcepid)));
1800  }
1801 
1802  /*
1803  * If there are no serializable transactions which are not read-only, we
1804  * can "opt out" of predicate locking and conflict checking for a
1805  * read-only transaction.
1806  *
1807  * The reason this is safe is that a read-only transaction can only become
1808  * part of a dangerous structure if it overlaps a writable transaction
1809  * which in turn overlaps a writable transaction which committed before
1810  * the read-only transaction started. A new writable transaction can
1811  * overlap this one, but it can't meet the other condition of overlapping
1812  * a transaction which committed before this one started.
1813  */
1815  {
1816  ReleasePredXact(sxact);
1817  LWLockRelease(SerializableXactHashLock);
1818  return snapshot;
1819  }
1820 
1821  /* Initialize the structure. */
1822  sxact->vxid = vxid;
1826  dlist_init(&(sxact->outConflicts));
1827  dlist_init(&(sxact->inConflicts));
1829  sxact->topXid = GetTopTransactionIdIfAny();
1831  sxact->xmin = snapshot->xmin;
1832  sxact->pid = MyProcPid;
1833  sxact->pgprocno = MyProcNumber;
1834  dlist_init(&sxact->predicateLocks);
1835  dlist_node_init(&sxact->finishedLink);
1836  sxact->flags = 0;
1837  if (XactReadOnly)
1838  {
1839  dlist_iter iter;
1840 
1841  sxact->flags |= SXACT_FLAG_READ_ONLY;
1842 
1843  /*
1844  * Register all concurrent r/w transactions as possible conflicts; if
1845  * all of them commit without any outgoing conflicts to earlier
1846  * transactions then this snapshot can be deemed safe (and we can run
1847  * without tracking predicate locks).
1848  */
1850  {
1851  othersxact = dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
1852 
1853  if (!SxactIsCommitted(othersxact)
1854  && !SxactIsDoomed(othersxact)
1855  && !SxactIsReadOnly(othersxact))
1856  {
1857  SetPossibleUnsafeConflict(sxact, othersxact);
1858  }
1859  }
1860 
1861  /*
1862  * If we didn't find any possibly unsafe conflicts because every
1863  * uncommitted writable transaction turned out to be doomed, then we
1864  * can "opt out" immediately. See comments above the earlier check
1865  * for PredXact->WritableSxactCount == 0.
1866  */
1868  {
1869  ReleasePredXact(sxact);
1870  LWLockRelease(SerializableXactHashLock);
1871  return snapshot;
1872  }
1873  }
1874  else
1875  {
1879  }
1880 
1881  /* Maintain serializable global xmin info. */
1883  {
1885  PredXact->SxactGlobalXmin = snapshot->xmin;
1887  SerialSetActiveSerXmin(snapshot->xmin);
1888  }
1889  else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
1890  {
1893  }
1894  else
1895  {
1897  }
1898 
1899  MySerializableXact = sxact;
1900  MyXactDidWrite = false; /* haven't written anything yet */
1901 
1902  LWLockRelease(SerializableXactHashLock);
1903 
1905 
1906  return snapshot;
1907 }
int MyProcPid
Definition: globals.c:45
int MaxBackends
Definition: globals.c:143
static void dlist_node_init(dlist_node *node)
Definition: ilist.h:325
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:77
static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
Definition: predicate.c:667
static void ReleasePredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:597
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:583
static void SerialSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:970
static void SummarizeOldestCommittedSxact(void)
Definition: predicate.c:1473
#define SXACT_FLAG_READ_ONLY
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:2166
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition: procarray.c:2525
PGPROC * MyProc
Definition: proc.c:68
int MyProcNumber
Definition: proc.c:69
Definition: proc.h:162
SerCommitSeqNo LastSxactCommitSeqNo
VirtualTransactionId vxid
SerCommitSeqNo prepareSeqNo
TransactionId xmin
Definition: snapshot.h:157
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:314
#define InvalidTransactionId
Definition: transam.h:31
int max_prepared_xacts
Definition: twophase.c:118

References PredXactListData::activeList, Assert(), SERIALIZABLEXACT::commitSeqNo, CreateLocalPredicateLockHash(), CreatePredXact(), dlist_iter::cur, dlist_container, dlist_foreach, dlist_init(), dlist_is_empty(), dlist_node_init(), elog(), ereport, errcode(), errdetail(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, SERIALIZABLEXACT::flags, GET_VXID_FROM_PGPROC, GetSnapshotData(), GetTopTransactionIdIfAny(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, InvalidSerializableXact, InvalidTransactionId, IsInParallelMode(), SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), max_prepared_xacts, MaxBackends, MyProc, MyProcNumber, MyProcPid, MySerializableXact, MyXactDidWrite, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::predicateLocks, PredXact, SERIALIZABLEXACT::prepareSeqNo, ProcArrayInstallImportedXmin(), RecoveryInProgress(), ReleasePredXact(), SERIALIZABLEXACT::SeqNo, SerialSetActiveSerXmin(), SetPossibleUnsafeConflict(), SummarizeOldestCommittedSxact(), SXACT_FLAG_READ_ONLY, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactIsCommitted, SxactIsDoomed, SxactIsReadOnly, SERIALIZABLEXACT::topXid, TransactionIdEquals, TransactionIdFollows(), TransactionIdIsValid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, XactReadOnly, SERIALIZABLEXACT::xmin, and SnapshotData::xmin.

Referenced by GetSafeSnapshot(), GetSerializableTransactionSnapshot(), and SetSerializableTransactionSnapshot().

◆ InitPredicateLocks()

void InitPredicateLocks ( void  )

Definition at line 1125 of file predicate.c.

1126 {
1127  HASHCTL info;
1128  long max_table_size;
1129  Size requestSize;
1130  bool found;
1131 
1132 #ifndef EXEC_BACKEND
1134 #endif
1135 
1136  /*
1137  * Compute size of predicate lock target hashtable. Note these
1138  * calculations must agree with PredicateLockShmemSize!
1139  */
1140  max_table_size = NPREDICATELOCKTARGETENTS();
1141 
1142  /*
1143  * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1144  * per-predicate-lock-target information.
1145  */
1146  info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1147  info.entrysize = sizeof(PREDICATELOCKTARGET);
1149 
1150  PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1151  max_table_size,
1152  max_table_size,
1153  &info,
1154  HASH_ELEM | HASH_BLOBS |
1156 
1157  /*
1158  * Reserve a dummy entry in the hash table; we use it to make sure there's
1159  * always one entry available when we need to split or combine a page,
1160  * because running out of space there could mean aborting a
1161  * non-serializable transaction.
1162  */
1163  if (!IsUnderPostmaster)
1164  {
1166  HASH_ENTER, &found);
1167  Assert(!found);
1168  }
1169 
1170  /* Pre-calculate the hash and partition lock of the scratch entry */
1173 
1174  /*
1175  * Allocate hash table for PREDICATELOCK structs. This stores per
1176  * xact-lock-of-a-target information.
1177  */
1178  info.keysize = sizeof(PREDICATELOCKTAG);
1179  info.entrysize = sizeof(PREDICATELOCK);
1180  info.hash = predicatelock_hash;
1182 
1183  /* Assume an average of 2 xacts per target */
1184  max_table_size *= 2;
1185 
1186  PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1187  max_table_size,
1188  max_table_size,
1189  &info,
1192 
1193  /*
1194  * Compute size for serializable transaction hashtable. Note these
1195  * calculations must agree with PredicateLockShmemSize!
1196  */
1197  max_table_size = (MaxBackends + max_prepared_xacts);
1198 
1199  /*
1200  * Allocate a list to hold information on transactions participating in
1201  * predicate locking.
1202  *
1203  * Assume an average of 10 predicate locking transactions per backend.
1204  * This allows aggressive cleanup while detail is present before data must
1205  * be summarized for storage in SLRU and the "dummy" transaction.
1206  */
1207  max_table_size *= 10;
1208 
1209  PredXact = ShmemInitStruct("PredXactList",
1211  &found);
1212  Assert(found == IsUnderPostmaster);
1213  if (!found)
1214  {
1215  int i;
1216 
1225  requestSize = mul_size((Size) max_table_size,
1226  sizeof(SERIALIZABLEXACT));
1227  PredXact->element = ShmemAlloc(requestSize);
1228  /* Add all elements to available list, clean. */
1229  memset(PredXact->element, 0, requestSize);
1230  for (i = 0; i < max_table_size; i++)
1231  {
1235  }
1252  }
1253  /* This never changes, so let's keep a local copy. */
1255 
1256  /*
1257  * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1258  * information for serializable transactions which have accessed data.
1259  */
1260  info.keysize = sizeof(SERIALIZABLEXIDTAG);
1261  info.entrysize = sizeof(SERIALIZABLEXID);
1262 
1263  SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1264  max_table_size,
1265  max_table_size,
1266  &info,
1267  HASH_ELEM | HASH_BLOBS |
1268  HASH_FIXED_SIZE);
1269 
1270  /*
1271  * Allocate space for tracking rw-conflicts in lists attached to the
1272  * transactions.
1273  *
1274  * Assume an average of 5 conflicts per transaction. Calculations suggest
1275  * that this will prevent resource exhaustion in even the most pessimal
1276  * loads up to max_connections = 200 with all 200 connections pounding the
1277  * database with serializable transactions. Beyond that, there may be
1278  * occasional transactions canceled when trying to flag conflicts. That's
1279  * probably OK.
1280  */
1281  max_table_size *= 5;
1282 
1283  RWConflictPool = ShmemInitStruct("RWConflictPool",
1285  &found);
1286  Assert(found == IsUnderPostmaster);
1287  if (!found)
1288  {
1289  int i;
1290 
1292  requestSize = mul_size((Size) max_table_size,
1294  RWConflictPool->element = ShmemAlloc(requestSize);
1295  /* Add all elements to available list, clean. */
1296  memset(RWConflictPool->element, 0, requestSize);
1297  for (i = 0; i < max_table_size; i++)
1298  {
1301  }
1302  }
1303 
1304  /*
1305  * Create or attach to the header for the list of finished serializable
1306  * transactions.
1307  */
1309  ShmemInitStruct("FinishedSerializableTransactions",
1310  sizeof(dlist_head),
1311  &found);
1312  Assert(found == IsUnderPostmaster);
1313  if (!found)
1315 
1316  /*
1317  * Initialize the SLRU storage for old committed serializable
1318  * transactions.
1319  */
1320  SerialInit();
1321 }
size_t Size
Definition: c.h:594
bool IsUnderPostmaster
Definition: globals.c:116
#define HASH_FUNCTION
Definition: hsearch.h:98
#define HASH_FIXED_SIZE
Definition: hsearch.h:105
#define HASH_PARTITION
Definition: hsearch.h:92
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:74
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:703
@ LWTRANCHE_PER_XACT_PREDICATE_LIST
Definition: lwlock.h:204
static LWLock * ScratchPartitionLock
Definition: predicate.c:409
static uint32 ScratchTargetTagHash
Definition: predicate.c:408
static uint32 predicatelock_hash(const void *key, Size keysize)
Definition: predicate.c:1389
static void SerialInit(void)
Definition: predicate.c:807
static const PREDICATELOCKTARGETTAG ScratchTargetTag
Definition: predicate.c:407
#define NPREDICATELOCKTARGETENTS()
Definition: predicate.c:265
static RWConflictPoolHeader RWConflictPool
Definition: predicate.c:391
#define RWConflictDataSize
#define FirstNormalSerCommitSeqNo
struct PREDICATELOCKTAG PREDICATELOCKTAG
#define PredXactListDataSize
#define RWConflictPoolHeaderDataSize
struct SERIALIZABLEXIDTAG SERIALIZABLEXIDTAG
struct PREDICATELOCKTARGET PREDICATELOCKTARGET
struct SERIALIZABLEXID SERIALIZABLEXID
#define SXACT_FLAG_COMMITTED
struct PREDICATELOCK PREDICATELOCK
#define INVALID_PGPROCNO
Definition: proc.h:85
void * ShmemAlloc(Size size)
Definition: shmem.c:153
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:388
Size mul_size(Size s1, Size s2)
Definition: shmem.c:511
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:333
HashValueFunc hash
Definition: hsearch.h:78
long num_partitions
Definition: hsearch.h:68
SERIALIZABLEXACT * element
SERIALIZABLEXACT * OldCommittedSxact

References PredXactListData::activeList, Assert(), PredXactListData::availableList, RWConflictPoolHeaderData::availableList, PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, CreatePredXact(), dlist_init(), dlist_node_init(), dlist_push_tail(), PredXactListData::element, RWConflictPoolHeaderData::element, HASHCTL::entrysize, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, FirstNormalSerCommitSeqNo, SERIALIZABLEXACT::flags, HASHCTL::hash, HASH_BLOBS, HASH_ELEM, HASH_ENTER, HASH_FIXED_SIZE, HASH_FUNCTION, HASH_PARTITION, hash_search(), PredXactListData::HavePartialClearedThrough, i, SERIALIZABLEXACT::inConflicts, INVALID_PGPROCNO, InvalidTransactionId, IsUnderPostmaster, HASHCTL::keysize, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, LWLockInitialize(), LWTRANCHE_PER_XACT_PREDICATE_LIST, max_prepared_xacts, MaxBackends, mul_size(), NPREDICATELOCKTARGETENTS, HASHCTL::num_partitions, NUM_PREDICATELOCK_PARTITIONS, OldCommittedSxact, PredXactListData::OldCommittedSxact, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::perXactPredicateListLock, SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, predicatelock_hash(), PredicateLockHash, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetHash, PredicateLockTargetTagHashCode, PredXact, PredXactListDataSize, SERIALIZABLEXACT::prepareSeqNo, RWConflictDataSize, RWConflictPool, RWConflictPoolHeaderDataSize, ScratchPartitionLock, ScratchTargetTag, ScratchTargetTagHash, SERIALIZABLEXACT::SeqNo, SerialInit(), SerializableXidHash, SetInvalidVirtualTransactionId, ShmemAlloc(), ShmemInitHash(), ShmemInitStruct(), SXACT_FLAG_COMMITTED, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SERIALIZABLEXACT::topXid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, SERIALIZABLEXACT::xactLink, and SERIALIZABLEXACT::xmin.

Referenced by CreateOrAttachShmemStructs().

◆ MaxPredicateChildLocks()

static int MaxPredicateChildLocks ( const PREDICATELOCKTARGETTAG tag)
static

Definition at line 2259 of file predicate.c.

2260 {
2261  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2262  {
2263  case PREDLOCKTAG_RELATION:
2268 
2269  case PREDLOCKTAG_PAGE:
2271 
2272  case PREDLOCKTAG_TUPLE:
2273 
2274  /*
2275  * not reachable: nothing is finer-granularity than a tuple, so we
2276  * should never try to promote to it.
2277  */
2278  Assert(false);
2279  return 0;
2280  }
2281 
2282  /* not reachable */
2283  Assert(false);
2284  return 0;
2285 }
int max_predicate_locks_per_page
Definition: predicate.c:374
int max_predicate_locks_per_relation
Definition: predicate.c:373

References Assert(), GET_PREDICATELOCKTARGETTAG_TYPE, max_predicate_locks_per_page, max_predicate_locks_per_relation, max_predicate_locks_per_xact, PREDLOCKTAG_PAGE, PREDLOCKTAG_RELATION, and PREDLOCKTAG_TUPLE.

Referenced by CheckAndPromotePredicateLockRequest().

◆ OnConflict_CheckForSerializationFailure()

static void OnConflict_CheckForSerializationFailure ( const SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4506 of file predicate.c.

4508 {
4509  bool failure;
4510 
4511  Assert(LWLockHeldByMe(SerializableXactHashLock));
4512 
4513  failure = false;
4514 
4515  /*------------------------------------------------------------------------
4516  * Check for already-committed writer with rw-conflict out flagged
4517  * (conflict-flag on W means that T2 committed before W):
4518  *
4519  * R ------> W ------> T2
4520  * rw rw
4521  *
4522  * That is a dangerous structure, so we must abort. (Since the writer
4523  * has already committed, we must be the reader)
4524  *------------------------------------------------------------------------
4525  */
4526  if (SxactIsCommitted(writer)
4527  && (SxactHasConflictOut(writer) || SxactHasSummaryConflictOut(writer)))
4528  failure = true;
4529 
4530  /*------------------------------------------------------------------------
4531  * Check whether the writer has become a pivot with an out-conflict
4532  * committed transaction (T2), and T2 committed first:
4533  *
4534  * R ------> W ------> T2
4535  * rw rw
4536  *
4537  * Because T2 must've committed first, there is no anomaly if:
4538  * - the reader committed before T2
4539  * - the writer committed before T2
4540  * - the reader is a READ ONLY transaction and the reader was concurrent
4541  * with T2 (= reader acquired its snapshot before T2 committed)
4542  *
4543  * We also handle the case that T2 is prepared but not yet committed
4544  * here. In that case T2 has already checked for conflicts, so if it
4545  * commits first, making the above conflict real, it's too late for it
4546  * to abort.
4547  *------------------------------------------------------------------------
4548  */
4549  if (!failure && SxactHasSummaryConflictOut(writer))
4550  failure = true;
4551  else if (!failure)
4552  {
4553  dlist_iter iter;
4554 
4555  dlist_foreach(iter, &writer->outConflicts)
4556  {
4557  RWConflict conflict =
4558  dlist_container(RWConflictData, outLink, iter.cur);
4559  SERIALIZABLEXACT *t2 = conflict->sxactIn;
4560 
4561  if (SxactIsPrepared(t2)
4562  && (!SxactIsCommitted(reader)
4563  || t2->prepareSeqNo <= reader->commitSeqNo)
4564  && (!SxactIsCommitted(writer)
4565  || t2->prepareSeqNo <= writer->commitSeqNo)
4566  && (!SxactIsReadOnly(reader)
4567  || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
4568  {
4569  failure = true;
4570  break;
4571  }
4572  }
4573  }
4574 
4575  /*------------------------------------------------------------------------
4576  * Check whether the reader has become a pivot with a writer
4577  * that's committed (or prepared):
4578  *
4579  * T0 ------> R ------> W
4580  * rw rw
4581  *
4582  * Because W must've committed first for an anomaly to occur, there is no
4583  * anomaly if:
4584  * - T0 committed before the writer
4585  * - T0 is READ ONLY, and overlaps the writer
4586  *------------------------------------------------------------------------
4587  */
4588  if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
4589  {
4590  if (SxactHasSummaryConflictIn(reader))
4591  {
4592  failure = true;
4593  }
4594  else
4595  {
4596  dlist_iter iter;
4597 
4598  /*
4599  * The unconstify is needed as we have no const version of
4600  * dlist_foreach().
4601  */
4602  dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->inConflicts)
4603  {
4604  const RWConflict conflict =
4605  dlist_container(RWConflictData, inLink, iter.cur);
4606  const SERIALIZABLEXACT *t0 = conflict->sxactOut;
4607 
4608  if (!SxactIsDoomed(t0)
4609  && (!SxactIsCommitted(t0)
4610  || t0->commitSeqNo >= writer->prepareSeqNo)
4611  && (!SxactIsReadOnly(t0)
4612  || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
4613  {
4614  failure = true;
4615  break;
4616  }
4617  }
4618  }
4619  }
4620 
4621  if (failure)
4622  {
4623  /*
4624  * We have to kill a transaction to avoid a possible anomaly from
4625  * occurring. If the writer is us, we can just ereport() to cause a
4626  * transaction abort. Otherwise we flag the writer for termination,
4627  * causing it to abort when it tries to commit. However, if the writer
4628  * is a prepared transaction, already prepared, we can't abort it
4629  * anymore, so we have to kill the reader instead.
4630  */
4631  if (MySerializableXact == writer)
4632  {
4633  LWLockRelease(SerializableXactHashLock);
4634  ereport(ERROR,
4636  errmsg("could not serialize access due to read/write dependencies among transactions"),
4637  errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
4638  errhint("The transaction might succeed if retried.")));
4639  }
4640  else if (SxactIsPrepared(writer))
4641  {
4642  LWLockRelease(SerializableXactHashLock);
4643 
4644  /* if we're not the writer, we have to be the reader */
4645  Assert(MySerializableXact == reader);
4646  ereport(ERROR,
4648  errmsg("could not serialize access due to read/write dependencies among transactions"),
4649  errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
4650  errhint("The transaction might succeed if retried.")));
4651  }
4652  writer->flags |= SXACT_FLAG_DOOMED;
4653  }
4654 }
#define unconstify(underlying_type, expr)
Definition: c.h:1234

References Assert(), SERIALIZABLEXACT::commitSeqNo, dlist_iter::cur, dlist_container, dlist_foreach, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LWLockHeldByMe(), LWLockRelease(), MySerializableXact, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::prepareSeqNo, SERIALIZABLEXACT::SeqNo, SXACT_FLAG_DOOMED, SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, RWConflictData::sxactIn, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, RWConflictData::sxactOut, SERIALIZABLEXACT::topXid, and unconstify.

Referenced by FlagRWConflict().

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

Definition at line 1978 of file predicate.c.

1979 {
1980  PREDICATELOCKTARGETTAG targettag;
1981  uint32 targettaghash;
1982  LWLock *partitionLock;
1983  PREDICATELOCKTARGET *target;
1984 
1986  relation->rd_locator.dbOid,
1987  relation->rd_id,
1988  blkno);
1989 
1990  targettaghash = PredicateLockTargetTagHashCode(&targettag);
1991  partitionLock = PredicateLockHashPartitionLock(targettaghash);
1992  LWLockAcquire(partitionLock, LW_SHARED);
1993  target = (PREDICATELOCKTARGET *)
1995  &targettag, targettaghash,
1996  HASH_FIND, NULL);
1997  LWLockRelease(partitionLock);
1998 
1999  return (target != NULL);
2000 }

References RelFileLocator::dbOid, HASH_FIND, hash_search_with_hash_value(), LW_SHARED, LWLockAcquire(), LWLockRelease(), PredicateLockHashPartitionLock, PredicateLockTargetHash, PredicateLockTargetTagHashCode, RelationData::rd_id, RelationData::rd_locator, and SET_PREDICATELOCKTARGETTAG_PAGE.

◆ PostPrepare_PredicateLocks()

void PostPrepare_PredicateLocks ( TransactionId  xid)

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4673 of file predicate.c.

4674 {
4675  dlist_iter near_iter;
4676 
4678  return;
4679 
4681 
4682  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4683 
4684  /*
4685  * Check if someone else has already decided that we need to die. Since
4686  * we set our own DOOMED flag when partially releasing, ignore in that
4687  * case.
4688  */
4691  {
4692  LWLockRelease(SerializableXactHashLock);
4693  ereport(ERROR,
4695  errmsg("could not serialize access due to read/write dependencies among transactions"),
4696  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4697  errhint("The transaction might succeed if retried.")));
4698  }
4699 
4701  {
4702  RWConflict nearConflict =
4703  dlist_container(RWConflictData, inLink, near_iter.cur);
4704 
4705  if (!SxactIsCommitted(nearConflict->sxactOut)
4706  && !SxactIsDoomed(nearConflict->sxactOut))
4707  {
4708  dlist_iter far_iter;
4709 
4710  dlist_foreach(far_iter, &nearConflict->sxactOut->inConflicts)
4711  {
4712  RWConflict farConflict =
4713  dlist_container(RWConflictData, inLink, far_iter.cur);
4714 
4715  if (farConflict->sxactOut == MySerializableXact
4716  || (!SxactIsCommitted(farConflict->sxactOut)
4717  && !SxactIsReadOnly(farConflict->sxactOut)
4718  && !SxactIsDoomed(farConflict->sxactOut)))
4719  {
4720  /*
4721  * Normally, we kill the pivot transaction to make sure we
4722  * make progress if the failing transaction is retried.
4723  * However, we can't kill it if it's already prepared, so
4724  * in that case we commit suicide instead.
4725  */
4726  if (SxactIsPrepared(nearConflict->sxactOut))
4727  {
4728  LWLockRelease(SerializableXactHashLock);
4729  ereport(ERROR,
4731  errmsg("could not serialize access due to read/write dependencies among transactions"),
4732  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4733  errhint("The transaction might succeed if retried.")));
4734  }
4735  nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4736  break;
4737  }
4738  }
4739  }
4740  }
4741 
4744 
4745  LWLockRelease(SerializableXactHashLock);
4746 }
#define SxactIsPartiallyReleased(sxact)
Definition: predicate.c:294
#define SXACT_FLAG_PREPARED

References Assert(), dlist_iter::cur, dlist_container, dlist_foreach, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::inConflicts, InvalidSerializableXact, IsolationIsSerializable, PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, PredXact, SERIALIZABLEXACT::prepareSeqNo, SXACT_FLAG_DOOMED, SXACT_FLAG_PREPARED, SxactIsCommitted, SxactIsDoomed, SxactIsPartiallyReleased, SxactIsPrepared, SxactIsReadOnly, and RWConflictData::sxactOut.

Referenced by CommitTransaction(), and PrepareTransaction().

◆ predicatelock_hash()

static uint32 predicatelock_hash ( const void *  key,
Size  keysize 
)
static

Definition at line 1389 of file predicate.c.

1390 {
1391  const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
1392  uint32 targethash;
1393 
1394  Assert(keysize == sizeof(PREDICATELOCKTAG));
1395 
1396  /* Look into the associated target object, and compute its hash code */
1397  targethash = PredicateLockTargetTagHashCode(&predicatelocktag->myTarget->tag);
1398 
1399  return PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash);
1400 }

References Assert(), sort-test::key, PREDICATELOCKTAG::myTarget, PredicateLockHashCodeFromTargetHashCode, PredicateLockTargetTagHashCode, and PREDICATELOCKTARGET::tag.

Referenced by InitPredicateLocks().

◆ predicatelock_twophase_recover()

void predicatelock_twophase_recover ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 4879 of file predicate.c.

4881 {
4882  TwoPhasePredicateRecord *record;
4883 
4884  Assert(len == sizeof(TwoPhasePredicateRecord));
4885 
4886  record = (TwoPhasePredicateRecord *) recdata;
4887 
4888  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
4889  (record->type == TWOPHASEPREDICATERECORD_LOCK));
4890 
4891  if (record->type == TWOPHASEPREDICATERECORD_XACT)
4892  {
4893  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4894  TwoPhasePredicateXactRecord *xactRecord;
4895  SERIALIZABLEXACT *sxact;
4896  SERIALIZABLEXID *sxid;
4897  SERIALIZABLEXIDTAG sxidtag;
4898  bool found;
4899 
4900  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4901 
4902  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4903  sxact = CreatePredXact();
4904  if (!sxact)
4905  ereport(ERROR,
4906  (errcode(ERRCODE_OUT_OF_MEMORY),
4907  errmsg("out of shared memory")));
4908 
4909  /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
4910  sxact->vxid.backendId = InvalidBackendId;
4912  sxact->pid = 0;
4913  sxact->pgprocno = INVALID_PGPROCNO;
4914 
4915  /* a prepared xact hasn't committed yet */
4919 
4921 
4922  /*
4923  * Don't need to track this; no transactions running at the time the
4924  * recovered xact started are still active, except possibly other
4925  * prepared xacts and we don't care whether those are RO_SAFE or not.
4926  */
4928 
4929  dlist_init(&(sxact->predicateLocks));
4930  dlist_node_init(&sxact->finishedLink);
4931 
4932  sxact->topXid = xid;
4933  sxact->xmin = xactRecord->xmin;
4934  sxact->flags = xactRecord->flags;
4935  Assert(SxactIsPrepared(sxact));
4936  if (!SxactIsReadOnly(sxact))
4937  {
4941  }
4942 
4943  /*
4944  * We don't know whether the transaction had any conflicts or not, so
4945  * we'll conservatively assume that it had both a conflict in and a
4946  * conflict out, and represent that with the summary conflict flags.
4947  */
4948  dlist_init(&(sxact->outConflicts));
4949  dlist_init(&(sxact->inConflicts));
4952 
4953  /* Register the transaction's xid */
4954  sxidtag.xid = xid;
4956  &sxidtag,
4957  HASH_ENTER, &found);
4958  Assert(sxid != NULL);
4959  Assert(!found);
4960  sxid->myXact = (SERIALIZABLEXACT *) sxact;
4961 
4962  /*
4963  * Update global xmin. Note that this is a special case compared to
4964  * registering a normal transaction, because the global xmin might go
4965  * backwards. That's OK, because until recovery is over we're not
4966  * going to complete any transactions or create any non-prepared
4967  * transactions, so there's no danger of throwing away.
4968  */
4971  {
4972  PredXact->SxactGlobalXmin = sxact->xmin;
4974  SerialSetActiveSerXmin(sxact->xmin);
4975  }
4976  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
4977  {
4980  }
4981 
4982  LWLockRelease(SerializableXactHashLock);
4983  }
4984  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
4985  {
4986  /* Lock record. Recreate the PREDICATELOCK */
4987  TwoPhasePredicateLockRecord *lockRecord;
4988  SERIALIZABLEXID *sxid;
4989  SERIALIZABLEXACT *sxact;
4990  SERIALIZABLEXIDTAG sxidtag;
4991  uint32 targettaghash;
4992 
4993  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
4994  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
4995 
4996  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4997  sxidtag.xid = xid;
4998  sxid = (SERIALIZABLEXID *)
4999  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
5000  LWLockRelease(SerializableXactHashLock);
5001 
5002  Assert(sxid != NULL);
5003  sxact = sxid->myXact;
5004  Assert(sxact != InvalidSerializableXact);
5005 
5006  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5007  }
5008 }
#define InvalidBackendId
Definition: backendid.h:23
uint32 LocalTransactionId
Definition: c.h:643
const void size_t len
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2423
#define RecoverySerCommitSeqNo
LocalTransactionId localTransactionId
Definition: lock.h:62
BackendId backendId
Definition: lock.h:61

References Assert(), VirtualTransactionId::backendId, SERIALIZABLEXACT::commitSeqNo, CreatePredicateLock(), CreatePredXact(), TwoPhasePredicateRecord::data, dlist_init(), dlist_node_init(), ereport, errcode(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, SERIALIZABLEXACT::flags, TwoPhasePredicateXactRecord::flags, HASH_ENTER, HASH_FIND, hash_search(), SERIALIZABLEXACT::inConflicts, INVALID_PGPROCNO, InvalidBackendId, InvalidSerCommitSeqNo, InvalidSerializableXact, InvalidTransactionId, SERIALIZABLEXACT::lastCommitBeforeSnapshot, len, VirtualTransactionId::localTransactionId, TwoPhasePredicateRecord::lockRecord, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_prepared_xacts, MaxBackends, SERIALIZABLEXID::myXact, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, PredXact, SERIALIZABLEXACT::prepareSeqNo, RecoverySerCommitSeqNo, SERIALIZABLEXACT::SeqNo, SerializableXidHash, SerialSetActiveSerXmin(), SXACT_FLAG_SUMMARY_CONFLICT_IN, SXACT_FLAG_SUMMARY_CONFLICT_OUT, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactIsPrepared, SxactIsReadOnly, TwoPhasePredicateLockRecord::target, SERIALIZABLEXACT::topXid, TransactionIdEquals, TransactionIdFollows(), TransactionIdIsValid, TWOPHASEPREDICATERECORD_LOCK, TWOPHASEPREDICATERECORD_XACT, TwoPhasePredicateRecord::type, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, TwoPhasePredicateRecord::xactRecord, SERIALIZABLEXIDTAG::xid, SERIALIZABLEXACT::xmin, and TwoPhasePredicateXactRecord::xmin.

◆ PredicateLockAcquire()

static void PredicateLockAcquire ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2487 of file predicate.c.

2488 {
2489  uint32 targettaghash;
2490  bool found;
2491  LOCALPREDICATELOCK *locallock;
2492 
2493  /* Do we have the lock already, or a covering lock? */
2494  if (PredicateLockExists(targettag))
2495  return;
2496 
2497  if (CoarserLockCovers(targettag))
2498  return;
2499 
2500  /* the same hash and LW lock apply to the lock target and the local lock. */
2501  targettaghash = PredicateLockTargetTagHashCode(targettag);
2502 
2503  /* Acquire lock in local table */
2504  locallock = (LOCALPREDICATELOCK *)
2506  targettag, targettaghash,
2507  HASH_ENTER, &found);
2508  locallock->held = true;
2509  if (!found)
2510  locallock->childLocks = 0;
2511 
2512  /* Actually create the lock */
2513  CreatePredicateLock(targettag, targettaghash, MySerializableXact);
2514 
2515  /*
2516  * Lock has been acquired. Check whether it should be promoted to a
2517  * coarser granularity, or whether there are finer-granularity locks to
2518  * clean up.
2519  */
2520  if (CheckAndPromotePredicateLockRequest(targettag))
2521  {
2522  /*
2523  * Lock request was promoted to a coarser-granularity lock, and that
2524  * lock was acquired. It will delete this lock and any of its
2525  * children, so we're done.
2526  */
2527  }
2528  else
2529  {
2530  /* Clean up any finer-granularity locks */
2532  DeleteChildTargetLocks(targettag);
2533  }
2534 }
static void DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
Definition: predicate.c:2184
static bool CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag)
Definition: predicate.c:2296
static bool CoarserLockCovers(const PREDICATELOCKTARGETTAG *newtargettag)
Definition: predicate.c:2081

References CheckAndPromotePredicateLockRequest(), LOCALPREDICATELOCK::childLocks, CoarserLockCovers(), CreatePredicateLock(), DeleteChildTargetLocks(), GET_PREDICATELOCKTARGETTAG_TYPE, HASH_ENTER, hash_search_with_hash_value(), LOCALPREDICATELOCK::held, LocalPredicateLockHash, MySerializableXact, PredicateLockExists(), PredicateLockTargetTagHashCode, and PREDLOCKTAG_TUPLE.

Referenced by CheckAndPromotePredicateLockRequest(), PredicateLockPage(), PredicateLockRelation(), and PredicateLockTID().

◆ PredicateLockExists()

static bool PredicateLockExists ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2015 of file predicate.c.

2016 {
2017  LOCALPREDICATELOCK *lock;
2018 
2019  /* check local hash table */
2021  targettag,
2022  HASH_FIND, NULL);
2023 
2024  if (!lock)
2025  return false;
2026 
2027  /*
2028  * Found entry in the table, but still need to check whether it's actually
2029  * held -- it could just be a parent of some held lock.
2030  */
2031  return lock->held;
2032 }

References HASH_FIND, hash_search(), LOCALPREDICATELOCK::held, and LocalPredicateLockHash.

Referenced by CoarserLockCovers(), PredicateLockAcquire(), and PredicateLockTID().

◆ PredicateLockingNeededForRelation()

static bool PredicateLockingNeededForRelation ( Relation  relation)
inlinestatic

Definition at line 499 of file predicate.c.

500 {
501  return !(relation->rd_id < FirstUnpinnedObjectId ||
502  RelationUsesLocalBuffers(relation));
503 }
#define RelationUsesLocalBuffers(relation)
Definition: rel.h:636
#define FirstUnpinnedObjectId
Definition: transam.h:196

References FirstUnpinnedObjectId, RelationData::rd_id, and RelationUsesLocalBuffers.

Referenced by DropAllPredicateLocksFromTable(), PredicateLockPageSplit(), SerializationNeededForRead(), and SerializationNeededForWrite().

◆ PredicateLockPage()

void PredicateLockPage ( Relation  relation,
BlockNumber  blkno,
Snapshot  snapshot 
)

◆ PredicateLockPageCombine()

void PredicateLockPageCombine ( Relation  relation,
BlockNumber  oldblkno,
BlockNumber  newblkno 
)

Definition at line 3199 of file predicate.c.

3201 {
3202  /*
3203  * Page combines differ from page splits in that we ought to be able to
3204  * remove the locks on the old page after transferring them to the new
3205  * page, instead of duplicating them. However, because we can't edit other
3206  * backends' local lock tables, removing the old lock would leave them
3207  * with an entry in their LocalPredicateLockHash for a lock they're not
3208  * holding, which isn't acceptable. So we wind up having to do the same
3209  * work as a page split, acquiring a lock on the new page and keeping the
3210  * old page locked too. That can lead to some false positives, but should
3211  * be rare in practice.
3212  */
3213  PredicateLockPageSplit(relation, oldblkno, newblkno);
3214 }
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3114

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

void PredicateLockPageSplit ( Relation  relation,
BlockNumber  oldblkno,
BlockNumber  newblkno 
)

Definition at line 3114 of file predicate.c.

3116 {
3117  PREDICATELOCKTARGETTAG oldtargettag;
3118  PREDICATELOCKTARGETTAG newtargettag;
3119  bool success;
3120 
3121  /*
3122  * Bail out quickly if there are no serializable transactions running.
3123  *
3124  * It's safe to do this check without taking any additional locks. Even if
3125  * a serializable transaction starts concurrently, we know it can't take
3126  * any SIREAD locks on the page being split because the caller is holding
3127  * the associated buffer page lock. Memory reordering isn't an issue; the
3128  * memory barrier in the LWLock acquisition guarantees that this read
3129  * occurs while the buffer page lock is held.
3130  */
3132  return;
3133 
3134  if (!PredicateLockingNeededForRelation(relation))
3135  return;
3136 
3137  Assert(oldblkno != newblkno);
3138  Assert(BlockNumberIsValid(oldblkno));
3139  Assert(BlockNumberIsValid(newblkno));
3140 
3141  SET_PREDICATELOCKTARGETTAG_PAGE(oldtargettag,
3142  relation->rd_locator.dbOid,
3143  relation->rd_id,
3144  oldblkno);
3145  SET_PREDICATELOCKTARGETTAG_PAGE(newtargettag,
3146  relation->rd_locator.dbOid,
3147  relation->rd_id,
3148  newblkno);
3149 
3150  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
3151 
3152  /*
3153  * Try copying the locks over to the new page's tag, creating it if
3154  * necessary.
3155  */
3157  newtargettag,
3158  false);
3159 
3160  if (!success)
3161  {
3162  /*
3163  * No more predicate lock entries are available. Failure isn't an
3164  * option here, so promote the page lock to a relation lock.
3165  */
3166 
3167  /* Get the parent relation lock's lock tag */
3168  success = GetParentPredicateLockTag(&oldtargettag,
3169  &newtargettag);
3170  Assert(success);
3171 
3172  /*
3173  * Move the locks to the parent. This shouldn't fail.
3174  *
3175  * Note that here we are removing locks held by other backends,
3176  * leading to a possible inconsistency in their local lock hash table.
3177  * This is OK because we're replacing it with a lock that covers the
3178  * old one.
3179  */
3181  newtargettag,
3182  true);
3183  Assert(success);
3184  }
3185 
3186  LWLockRelease(SerializablePredicateListLock);
3187 }
static bool BlockNumberIsValid(BlockNumber blockNumber)
Definition: block.h:71
static bool success
Definition: initdb.c:184
static bool TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag, PREDICATELOCKTARGETTAG newtargettag, bool removeOld)
Definition: predicate.c:2700

References Assert(), BlockNumberIsValid(), RelFileLocator::dbOid, GetParentPredicateLockTag(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PredicateLockingNeededForRelation(), PredXact, RelationData::rd_id, RelationData::rd_locator, SET_PREDICATELOCKTARGETTAG_PAGE, success, PredXactListData::SxactGlobalXmin, TransactionIdIsValid, and TransferPredicateLocksToNewTarget().

Referenced by _bt_insertonpg(), _hash_splitbucket(), createPostingTree(), ginPlaceToPage(), gistplacetopage(), and PredicateLockPageCombine().

◆ PredicateLockRelation()

void PredicateLockRelation ( Relation  relation,
Snapshot  snapshot 
)

Definition at line 2546 of file predicate.c.

2547 {
2549 
2550  if (!SerializationNeededForRead(relation, snapshot))
2551  return;
2552 
2554  relation->rd_locator.dbOid,
2555  relation->rd_id);
2556  PredicateLockAcquire(&tag);
2557 }

References RelFileLocator::dbOid, PredicateLockAcquire(), RelationData::rd_id, RelationData::rd_locator, SerializationNeededForRead(), and SET_PREDICATELOCKTARGETTAG_RELATION.

Referenced by _bt_endpoint(), _bt_first(), heap_beginscan(), and index_beginscan_internal().

◆ PredicateLockShmemSize()

Size PredicateLockShmemSize ( void  )

Definition at line 1327 of file predicate.c.

1328 {
1329  Size size = 0;
1330  long max_table_size;
1331 
1332  /* predicate lock target hash table */
1333  max_table_size = NPREDICATELOCKTARGETENTS();
1334  size = add_size(size, hash_estimate_size(max_table_size,
1335  sizeof(PREDICATELOCKTARGET)));
1336 
1337  /* predicate lock hash table */
1338  max_table_size *= 2;
1339  size = add_size(size, hash_estimate_size(max_table_size,
1340  sizeof(PREDICATELOCK)));
1341 
1342  /*
1343  * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
1344  * margin.
1345  */
1346  size = add_size(size, size / 10);
1347 
1348  /* transaction list */
1349  max_table_size = MaxBackends + max_prepared_xacts;
1350  max_table_size *= 10;
1351  size = add_size(size, PredXactListDataSize);
1352  size = add_size(size, mul_size((Size) max_table_size,
1353  sizeof(SERIALIZABLEXACT)));
1354 
1355  /* transaction xid table */
1356  size = add_size(size, hash_estimate_size(max_table_size,
1357  sizeof(SERIALIZABLEXID)));
1358 
1359  /* rw-conflict pool */
1360  max_table_size *= 5;
1361  size = add_size(size, RWConflictPoolHeaderDataSize);
1362  size = add_size(size, mul_size((Size) max_table_size,
1364 
1365  /* Head for list of finished serializable transactions. */
1366  size = add_size(size, sizeof(dlist_head));
1367 
1368  /* Shared memory structures for SLRU tracking of old committed xids. */
1369  size = add_size(size, sizeof(SerialControlData));
1371 
1372  return size;
1373 }
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:781
#define NUM_SERIAL_BUFFERS
Definition: predicate.h:31
Size add_size(Size s1, Size s2)
Definition: shmem.c:494
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:183

References add_size(), hash_estimate_size(), max_prepared_xacts, MaxBackends, mul_size(), NPREDICATELOCKTARGETENTS, NUM_SERIAL_BUFFERS, PredXactListDataSize, RWConflictDataSize, RWConflictPoolHeaderDataSize, and SimpleLruShmemSize().

Referenced by CalculateShmemSize().

◆ PredicateLockTID()

void PredicateLockTID ( Relation  relation,
ItemPointer  tid,
Snapshot  snapshot,
TransactionId  tuple_xid 
)

Definition at line 2591 of file predicate.c.

2593 {
2595 
2596  if (!SerializationNeededForRead(relation, snapshot))
2597  return;
2598 
2599  /*
2600  * Return if this xact wrote it.
2601  */
2602  if (relation->rd_index == NULL)
2603  {
2604  /* If we wrote it; we already have a write lock. */
2605  if (TransactionIdIsCurrentTransactionId(tuple_xid))
2606  return;
2607  }
2608 
2609  /*
2610  * Do quick-but-not-definitive test for a relation lock first. This will
2611  * never cause a return when the relation is *not* locked, but will
2612  * occasionally let the check continue when there really *is* a relation
2613  * level lock.
2614  */
2616  relation->rd_locator.dbOid,
2617  relation->rd_id);
2618  if (PredicateLockExists(&tag))
2619  return;
2620 
2622  relation->rd_locator.dbOid,
2623  relation->rd_id,
2626  PredicateLockAcquire(&tag);
2627 }
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:926

References RelFileLocator::dbOid, ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), PredicateLockAcquire(), PredicateLockExists(), RelationData::rd_id, RelationData::rd_index, RelationData::rd_locator, SerializationNeededForRead(), SET_PREDICATELOCKTARGETTAG_RELATION, SET_PREDICATELOCKTARGETTAG_TUPLE, and TransactionIdIsCurrentTransactionId().

Referenced by heap_fetch(), heap_hot_search_buffer(), and heapam_scan_bitmap_next_block().

◆ PredicateLockTwoPhaseFinish()

void PredicateLockTwoPhaseFinish ( TransactionId  xid,
bool  isCommit 
)

Definition at line 4852 of file predicate.c.

4853 {
4854  SERIALIZABLEXID *sxid;
4855  SERIALIZABLEXIDTAG sxidtag;
4856 
4857  sxidtag.xid = xid;
4858 
4859  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4860  sxid = (SERIALIZABLEXID *)
4861  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4862  LWLockRelease(SerializableXactHashLock);
4863 
4864  /* xid will not be found if it wasn't a serializable transaction */
4865  if (sxid == NULL)
4866  return;
4867 
4868  /* Release its locks */
4869  MySerializableXact = sxid->myXact;
4870  MyXactDidWrite = true; /* conservatively assume that we wrote
4871  * something */
4872  ReleasePredicateLocks(isCommit, false);
4873 }

References HASH_FIND, hash_search(), LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXID::myXact, MyXactDidWrite, ReleasePredicateLocks(), SerializableXidHash, and SERIALIZABLEXIDTAG::xid.

Referenced by FinishPreparedTransaction().

◆ RegisterPredicateLockingXid()

void RegisterPredicateLockingXid ( TransactionId  xid)

Definition at line 1929 of file predicate.c.

1930 {
1931  SERIALIZABLEXIDTAG sxidtag;
1932  SERIALIZABLEXID *sxid;
1933  bool found;
1934 
1935  /*
1936  * If we're not tracking predicate lock data for this transaction, we
1937  * should ignore the request and return quickly.
1938  */
1940  return;
1941 
1942  /* We should have a valid XID and be at the top level. */
1944 
1945  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1946 
1947  /* This should only be done once per transaction. */
1949 
1950  MySerializableXact->topXid = xid;
1951 
1952  sxidtag.xid = xid;
1954  &sxidtag,
1955  HASH_ENTER, &found);
1956  Assert(!found);
1957 
1958  /* Initialize the structure. */
1959  sxid->myXact = MySerializableXact;
1960  LWLockRelease(SerializableXactHashLock);
1961 }

References Assert(), HASH_ENTER, hash_search(), InvalidSerializableXact, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXID::myXact, SerializableXidHash, SERIALIZABLEXACT::topXid, TransactionIdIsValid, and SERIALIZABLEXIDTAG::xid.

Referenced by AssignTransactionId().

◆ ReleaseOneSerializableXact()

static void ReleaseOneSerializableXact ( SERIALIZABLEXACT sxact,
bool  partial,
bool  summarize 
)
static

Definition at line 3805 of file predicate.c.

3807 {
3808  SERIALIZABLEXIDTAG sxidtag;
3809  dlist_mutable_iter iter;
3810 
3811  Assert(sxact != NULL);
3812  Assert(SxactIsRolledBack(sxact) || SxactIsCommitted(sxact));
3813  Assert(partial || !SxactIsOnFinishedList(sxact));
3814  Assert(LWLockHeldByMe(SerializableFinishedListLock));
3815 
3816  /*
3817  * First release all the predicate locks held by this xact (or transfer
3818  * them to OldCommittedSxact if summarize is true)
3819  */
3820  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
3821  if (IsInParallelMode())
3823  dlist_foreach_modify(iter, &sxact->predicateLocks)
3824  {
3825  PREDICATELOCK *predlock =
3826  dlist_container(PREDICATELOCK, xactLink, iter.cur);
3827  PREDICATELOCKTAG tag;
3828  PREDICATELOCKTARGET *target;
3829  PREDICATELOCKTARGETTAG targettag;
3830  uint32 targettaghash;
3831  LWLock *partitionLock;
3832 
3833  tag = predlock->tag;
3834  target = tag.myTarget;
3835  targettag = target->tag;
3836  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3837  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3838 
3839  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3840 
3841  dlist_delete(&predlock->targetLink);
3842 
3845  targettaghash),
3846  HASH_REMOVE, NULL);
3847  if (summarize)
3848  {
3849  bool found;
3850 
3851  /* Fold into dummy transaction list. */
3852  tag.myXact = OldCommittedSxact;
3855  targettaghash),
3856  HASH_ENTER_NULL, &found);
3857  if (!predlock)
3858  ereport(ERROR,
3859  (errcode(ERRCODE_OUT_OF_MEMORY),
3860  errmsg("out of shared memory"),
3861  errhint("You might need to increase %s.", "max_pred_locks_per_transaction")));
3862  if (found)
3863  {
3864  Assert(predlock->commitSeqNo != 0);
3866  if (predlock->commitSeqNo < sxact->commitSeqNo)
3867  predlock->commitSeqNo = sxact->commitSeqNo;
3868  }
3869  else
3870  {
3872  &predlock->targetLink);
3874  &predlock->xactLink);
3875  predlock->commitSeqNo = sxact->commitSeqNo;
3876  }
3877  }
3878  else
3879  RemoveTargetIfNoLongerUsed(target, targettaghash);
3880 
3881  LWLockRelease(partitionLock);
3882  }
3883 
3884  /*
3885  * Rather than retail removal, just re-init the head after we've run
3886  * through the list.
3887  */
3888  dlist_init(&sxact->predicateLocks);
3889 
3890  if (IsInParallelMode())
3892  LWLockRelease(SerializablePredicateListLock);
3893 
3894  sxidtag.xid = sxact->topXid;
3895  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3896 
3897  /* Release all outConflicts (unless 'partial' is true) */
3898  if (!partial)
3899  {
3900  dlist_foreach_modify(iter, &sxact->outConflicts)
3901  {
3902  RWConflict conflict =
3903  dlist_container(RWConflictData, outLink, iter.cur);
3904 
3905  if (summarize)
3907  ReleaseRWConflict(conflict);
3908  }
3909  }
3910 
3911  /* Release all inConflicts. */
3912  dlist_foreach_modify(iter, &sxact->inConflicts)
3913  {
3914  RWConflict conflict =
3915  dlist_container(RWConflictData, inLink, iter.cur);
3916 
3917  if (summarize)
3919  ReleaseRWConflict(conflict);
3920  }
3921 
3922  /* Finally, get rid of the xid and the record of the transaction itself. */
3923  if (!partial)
3924  {
3925  if (sxidtag.xid != InvalidTransactionId)
3926  hash_search(SerializableXidHash, &sxidtag, HASH_REMOVE, NULL);
3927  ReleasePredXact(sxact);
3928  }
3929 
3930  LWLockRelease(SerializableXactHashLock);
3931 }
#define SxactIsOnFinishedList(sxact)
Definition: predicate.c:268
#define SxactIsRolledBack(sxact)
Definition: predicate.c:280

References Assert(), SERIALIZABLEXACT::commitSeqNo, PREDICATELOCK::commitSeqNo, dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_foreach_modify, dlist_init(), dlist_push_tail(), ereport, errcode(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, HASH_ENTER_NULL, HASH_REMOVE, hash_search(), hash_search_with_hash_value(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, InvalidTransactionId, IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, OldCommittedSxact, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::perXactPredicateListLock, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetTagHashCode, ReleasePredXact(), ReleaseRWConflict(), RemoveTargetIfNoLongerUsed(), SerializableXidHash, SXACT_FLAG_SUMMARY_CONFLICT_IN, SXACT_FLAG_SUMMARY_CONFLICT_OUT, RWConflictData::sxactIn, SxactIsCommitted, SxactIsOnFinishedList, SxactIsRolledBack, RWConflictData::sxactOut, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, SERIALIZABLEXACT::topXid, PREDICATELOCK::xactLink, and SERIALIZABLEXIDTAG::xid.

Referenced by ClearOldPredicateLocks(), ReleasePredicateLocks(), and SummarizeOldestCommittedSxact().

◆ ReleasePredicateLocks()

void ReleasePredicateLocks ( bool  isCommit,
bool  isReadOnlySafe 
)

Definition at line 3282 of file predicate.c.

3283 {
3284  bool partiallyReleasing = false;
3285  bool needToClear;
3286  SERIALIZABLEXACT *roXact;
3287  dlist_mutable_iter iter;
3288 
3289  /*
3290  * We can't trust XactReadOnly here, because a transaction which started
3291  * as READ WRITE can show as READ ONLY later, e.g., within
3292  * subtransactions. We want to flag a transaction as READ ONLY if it
3293  * commits without writing so that de facto READ ONLY transactions get the
3294  * benefit of some RO optimizations, so we will use this local variable to
3295  * get some cleanup logic right which is based on whether the transaction
3296  * was declared READ ONLY at the top level.
3297  */
3298  bool topLevelIsDeclaredReadOnly;
3299 
3300  /* We can't be both committing and releasing early due to RO_SAFE. */
3301  Assert(!(isCommit && isReadOnlySafe));
3302 
3303  /* Are we at the end of a transaction, that is, a commit or abort? */
3304  if (!isReadOnlySafe)
3305  {
3306  /*
3307  * Parallel workers mustn't release predicate locks at the end of
3308  * their transaction. The leader will do that at the end of its
3309  * transaction.
3310  */
3311  if (IsParallelWorker())
3312  {
3314  return;
3315  }
3316 
3317  /*
3318  * By the time the leader in a parallel query reaches end of
3319  * transaction, it has waited for all workers to exit.
3320  */
3322 
3323  /*
3324  * If the leader in a parallel query earlier stashed a partially
3325  * released SERIALIZABLEXACT for final clean-up at end of transaction
3326  * (because workers might still have been accessing it), then it's
3327  * time to restore it.
3328  */
3330  {
3335  }
3336  }
3337 
3339  {
3340  Assert(LocalPredicateLockHash == NULL);
3341  return;
3342  }
3343 
3344  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3345 
3346  /*
3347  * If the transaction is committing, but it has been partially released
3348  * already, then treat this as a roll back. It was marked as rolled back.
3349  */
3351  isCommit = false;
3352 
3353  /*
3354  * If we're called in the middle of a transaction because we discovered
3355  * that the SXACT_FLAG_RO_SAFE flag was set, then we'll partially release
3356  * it (that is, release the predicate locks and conflicts, but not the
3357  * SERIALIZABLEXACT itself) if we're the first backend to have noticed.
3358  */
3359  if (isReadOnlySafe && IsInParallelMode())
3360  {
3361  /*
3362  * The leader needs to stash a pointer to it, so that it can
3363  * completely release it at end-of-transaction.
3364  */
3365  if (!IsParallelWorker())
3367 
3368  /*
3369  * The first backend to reach this condition will partially release
3370  * the SERIALIZABLEXACT. All others will just clear their
3371  * backend-local state so that they stop doing SSI checks for the rest
3372  * of the transaction.
3373  */
3375  {
3376  LWLockRelease(SerializableXactHashLock);
3378  return;
3379  }
3380  else
3381  {
3383  partiallyReleasing = true;
3384  /* ... and proceed to perform the partial release below. */
3385  }
3386  }
3387  Assert(!isCommit || SxactIsPrepared(MySerializableXact));
3388  Assert(!isCommit || !SxactIsDoomed(MySerializableXact));
3392 
3393  /* may not be serializable during COMMIT/ROLLBACK PREPARED */
3395 
3396  /* We'd better not already be on the cleanup list. */
3398 
3399  topLevelIsDeclaredReadOnly = SxactIsReadOnly(MySerializableXact);
3400 
3401  /*
3402  * We don't hold XidGenLock lock here, assuming that TransactionId is
3403  * atomic!
3404  *
3405  * If this value is changing, we don't care that much whether we get the
3406  * old or new value -- it is just used to determine how far
3407  * SxactGlobalXmin must advance before this transaction can be fully
3408  * cleaned up. The worst that could happen is we wait for one more
3409  * transaction to complete before freeing some RAM; correctness of visible
3410  * behavior is not affected.
3411  */
3413 
3414  /*
3415  * If it's not a commit it's either a rollback or a read-only transaction
3416  * flagged SXACT_FLAG_RO_SAFE, and we can clear our locks immediately.
3417  */
3418  if (isCommit)
3419  {
3422  /* Recognize implicit read-only transaction (commit without write). */
3423  if (!MyXactDidWrite)
3425  }
3426  else
3427  {
3428  /*
3429  * The DOOMED flag indicates that we intend to roll back this
3430  * transaction and so it should not cause serialization failures for
3431  * other transactions that conflict with it. Note that this flag might
3432  * already be set, if another backend marked this transaction for
3433  * abort.
3434  *
3435  * The ROLLED_BACK flag further indicates that ReleasePredicateLocks
3436  * has been called, and so the SerializableXact is eligible for
3437  * cleanup. This means it should not be considered when calculating
3438  * SxactGlobalXmin.
3439  */
3442 
3443  /*
3444  * If the transaction was previously prepared, but is now failing due
3445  * to a ROLLBACK PREPARED or (hopefully very rare) error after the
3446  * prepare, clear the prepared flag. This simplifies conflict
3447  * checking.
3448  */
3450  }
3451 
3452  if (!topLevelIsDeclaredReadOnly)
3453  {
3455  if (--(PredXact->WritableSxactCount) == 0)
3456  {
3457  /*
3458  * Release predicate locks and rw-conflicts in for all committed
3459  * transactions. There are no longer any transactions which might
3460  * conflict with the locks and no chance for new transactions to
3461  * overlap. Similarly, existing conflicts in can't cause pivots,
3462  * and any conflicts in which could have completed a dangerous
3463  * structure would already have caused a rollback, so any
3464  * remaining ones must be benign.
3465  */
3467  }
3468  }
3469  else
3470  {
3471  /*
3472  * Read-only transactions: clear the list of transactions that might
3473  * make us unsafe. Note that we use 'inLink' for the iteration as
3474  * opposed to 'outLink' for the r/w xacts.
3475  */
3477  {
3478  RWConflict possibleUnsafeConflict =
3479  dlist_container(RWConflictData, inLink, iter.cur);
3480 
3481  Assert(!SxactIsReadOnly(possibleUnsafeConflict->sxactOut));
3482  Assert(MySerializableXact == possibleUnsafeConflict->sxactIn);
3483 
3484  ReleaseRWConflict(possibleUnsafeConflict);
3485  }
3486  }
3487 
3488  /* Check for conflict out to old committed transactions. */
3489  if (isCommit
3492  {
3493  /*
3494  * we don't know which old committed transaction we conflicted with,
3495  * so be conservative and use FirstNormalSerCommitSeqNo here
3496  */
3500  }
3501 
3502  /*
3503  * Release all outConflicts to committed transactions. If we're rolling
3504  * back clear them all. Set SXACT_FLAG_CONFLICT_OUT if any point to
3505  * previously committed transactions.
3506  */
3508  {
3509  RWConflict conflict =
3510  dlist_container(RWConflictData, outLink, iter.cur);
3511 
3512  if (isCommit
3514  && SxactIsCommitted(conflict->sxactIn))
3515  {
3520  }
3521 
3522  if (!isCommit
3523  || SxactIsCommitted(conflict->sxactIn)
3525  ReleaseRWConflict(conflict);
3526  }
3527 
3528  /*
3529  * Release all inConflicts from committed and read-only transactions. If
3530  * we're rolling back, clear them all.
3531  */
3533  {
3534  RWConflict conflict =
3535  dlist_container(RWConflictData, inLink, iter.cur);
3536 
3537  if (!isCommit
3538  || SxactIsCommitted(conflict->sxactOut)
3539  || SxactIsReadOnly(conflict->sxactOut))
3540  ReleaseRWConflict(conflict);
3541  }
3542 
3543  if (!topLevelIsDeclaredReadOnly)
3544  {
3545  /*
3546  * Remove ourselves from the list of possible conflicts for concurrent
3547  * READ ONLY transactions, flagging them as unsafe if we have a
3548  * conflict out. If any are waiting DEFERRABLE transactions, wake them
3549  * up if they are known safe or known unsafe.
3550  */
3552  {
3553  RWConflict possibleUnsafeConflict =
3554  dlist_container(RWConflictData, outLink, iter.cur);
3555 
3556  roXact = possibleUnsafeConflict->sxactIn;
3557  Assert(MySerializableXact == possibleUnsafeConflict->sxactOut);
3558  Assert(SxactIsReadOnly(roXact));
3559 
3560  /* Mark conflicted if necessary. */
3561  if (isCommit
3562  && MyXactDidWrite
3565  <= roXact->SeqNo.lastCommitBeforeSnapshot))
3566  {
3567  /*
3568  * This releases possibleUnsafeConflict (as well as all other
3569  * possible conflicts for roXact)
3570  */
3571  FlagSxactUnsafe(roXact);
3572  }
3573  else
3574  {
3575  ReleaseRWConflict(possibleUnsafeConflict);
3576 
3577  /*
3578  * If we were the last possible conflict, flag it safe. The
3579  * transaction can now safely release its predicate locks (but
3580  * that transaction's backend has to do that itself).
3581  */
3583  roXact->flags |= SXACT_FLAG_RO_SAFE;
3584  }
3585 
3586  /*
3587  * Wake up the process for a waiting DEFERRABLE transaction if we
3588  * now know it's either safe or conflicted.
3589  */
3590  if (SxactIsDeferrableWaiting(roXact) &&
3591  (SxactIsROUnsafe(roXact) || SxactIsROSafe(roXact)))
3592  ProcSendSignal(roXact->pgprocno);
3593  }
3594  }
3595 
3596  /*
3597  * Check whether it's time to clean up old transactions. This can only be
3598  * done when the last serializable transaction with the oldest xmin among
3599  * serializable transactions completes. We then find the "new oldest"
3600  * xmin and purge any transactions which finished before this transaction
3601  * was launched.
3602  *
3603  * For parallel queries in read-only transactions, it might run twice. We
3604  * only release the reference on the first call.
3605  */
3606  needToClear = false;
3607  if ((partiallyReleasing ||
3611  {
3613  if (--(PredXact->SxactGlobalXminCount) == 0)
3614  {
3616  needToClear = true;
3617  }
3618  }
3619 
3620  LWLockRelease(SerializableXactHashLock);
3621 
3622  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3623 
3624  /* Add this to the list of transactions to check for later cleanup. */
3625  if (isCommit)
3628 
3629  /*
3630  * If we're releasing a RO_SAFE transaction in parallel mode, we'll only
3631  * partially release it. That's necessary because other backends may have
3632  * a reference to it. The leader will release the SERIALIZABLEXACT itself
3633  * at the end of the transaction after workers have stopped running.
3634  */
3635  if (!isCommit)
3637  isReadOnlySafe && IsInParallelMode(),
3638  false);
3639 
3640  LWLockRelease(SerializableFinishedListLock);
3641 
3642  if (needToClear)
3644 
3646 }
static void SetNewSxactGlobalXmin(void)
Definition: predicate.c:3221
static void ReleasePredicateLocksLocal(void)
Definition: predicate.c:3649
static void ClearOldPredicateLocks(void)
Definition: predicate.c:3667
static void FlagSxactUnsafe(SERIALIZABLEXACT *sxact)
Definition: predicate.c:700
static SERIALIZABLEXACT * SavedSerializableXact
Definition: predicate.c:432
#define SXACT_FLAG_CONFLICT_OUT
#define SXACT_FLAG_ROLLED_BACK
#define SXACT_FLAG_PARTIALLY_RELEASED
#define SXACT_FLAG_RO_SAFE
void ProcSendSignal(int pgprocno)
Definition: proc.c:1859
FullTransactionId nextXid
Definition: transam.h:220
#define XidFromFullTransactionId(x)
Definition: transam.h:48
TransamVariablesData * TransamVariables
Definition: varsup.c:34

References Assert(), PredXactListData::CanPartialClearThrough, ClearOldPredicateLocks(), SERIALIZABLEXACT::commitSeqNo, dlist_mutable_iter::cur, dlist_container, dlist_foreach_modify, dlist_is_empty(), dlist_push_tail(), SERIALIZABLEXACT::earliestOutConflictCommit, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, FirstNormalSerCommitSeqNo, SERIALIZABLEXACT::flags, FlagSxactUnsafe(), SERIALIZABLEXACT::inConflicts, InvalidSerializableXact, IsInParallelMode(), IsolationIsSerializable, IsParallelWorker, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, LocalPredicateLockHash, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, MyXactDidWrite, TransamVariablesData::nextXid, SERIALIZABLEXACT::outConflicts, ParallelContextActive(), SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, PredXact, SERIALIZABLEXACT::prepareSeqNo, ProcSendSignal(), ReleaseOneSerializableXact(), ReleasePredicateLocksLocal(), ReleaseRWConflict(), SavedSerializableXact, SERIALIZABLEXACT::SeqNo, SetNewSxactGlobalXmin(), SXACT_FLAG_COMMITTED, SXACT_FLAG_CONFLICT_OUT, SXACT_FLAG_DOOMED, SXACT_FLAG_PARTIALLY_RELEASED, SXACT_FLAG_PREPARED, SXACT_FLAG_READ_ONLY, SXACT_FLAG_RO_SAFE, SXACT_FLAG_ROLLED_BACK, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactHasConflictOut, SxactHasSummaryConflictOut, RWConflictData::sxactIn, SxactIsCommitted, SxactIsDeferrableWaiting, SxactIsDoomed, SxactIsOnFinishedList, SxactIsPartiallyReleased, SxactIsPrepared, SxactIsReadOnly, SxactIsRolledBack, SxactIsROSafe, SxactIsROUnsafe, RWConflictData::sxactOut, TransactionIdEquals, TransamVariables, PredXactListData::WritableSxactCount, XidFromFullTransactionId, and SERIALIZABLEXACT::xmin.

Referenced by GetSafeSnapshot(), PredicateLockTwoPhaseFinish(), ResourceOwnerReleaseInternal(), and SerializationNeededForRead().

◆ ReleasePredicateLocksLocal()

static void ReleasePredicateLocksLocal ( void  )
static

Definition at line 3649 of file predicate.c.

3650 {
3652  MyXactDidWrite = false;
3653 
3654  /* Delete per-transaction lock table */
3655  if (LocalPredicateLockHash != NULL)
3656  {
3658  LocalPredicateLockHash = NULL;
3659  }
3660 }

References hash_destroy(), InvalidSerializableXact, LocalPredicateLockHash, MySerializableXact, and MyXactDidWrite.

Referenced by ReleasePredicateLocks().

◆ ReleasePredXact()

static void ReleasePredXact ( SERIALIZABLEXACT sxact)
static

Definition at line 597 of file predicate.c.

598 {
599  Assert(ShmemAddrIsValid(sxact));
600 
601  dlist_delete(&sxact->xactLink);
603 }
bool ShmemAddrIsValid(const void *addr)
Definition: shmem.c:275

References Assert(), PredXactListData::availableList, dlist_delete(), dlist_push_tail(), PredXact, ShmemAddrIsValid(), and SERIALIZABLEXACT::xactLink.

Referenced by GetSerializableTransactionSnapshotInt(), and ReleaseOneSerializableXact().

◆ ReleaseRWConflict()

static void ReleaseRWConflict ( RWConflict  conflict)
static

◆ RemoveScratchTarget()

static void RemoveScratchTarget ( bool  lockheld)
static

Definition at line 2110 of file predicate.c.

2111 {
2112  bool found;
2113 
2114  Assert(LWLockHeldByMe(SerializablePredicateListLock));
2115 
2116  if (!lockheld)
2121  HASH_REMOVE, &found);
2122  Assert(found);
2123  if (!lockheld)
2125 }

References Assert(), HASH_REMOVE, hash_search_with_hash_value(), LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), PredicateLockTargetHash, ScratchPartitionLock, ScratchTargetTag, and ScratchTargetTagHash.

Referenced by DropAllPredicateLocksFromTable(), and TransferPredicateLocksToNewTarget().

◆ RemoveTargetIfNoLongerUsed()

static void RemoveTargetIfNoLongerUsed ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

Definition at line 2153 of file predicate.c.

2154 {
2156 
2157  Assert(LWLockHeldByMe(SerializablePredicateListLock));
2158 
2159  /* Can't remove it until no locks at this target. */
2160  if (!dlist_is_empty(&target->predicateLocks))
2161  return;
2162 
2163  /* Actually remove the target. */
2165  &target->tag,
2166  targettaghash,
2167  HASH_REMOVE, NULL);
2168  Assert(rmtarget == target);
2169 }

References Assert(), dlist_is_empty(), HASH_REMOVE, hash_search_with_hash_value(), LWLockHeldByMe(), PG_USED_FOR_ASSERTS_ONLY, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, and PREDICATELOCKTARGET::tag.

Referenced by CheckTargetForConflictsIn(), ClearOldPredicateLocks(), DeleteChildTargetLocks(), DeleteLockTarget(), ReleaseOneSerializableXact(), and TransferPredicateLocksToNewTarget().

◆ RestoreScratchTarget()

static void RestoreScratchTarget ( bool  lockheld)
static

Definition at line 2131 of file predicate.c.

2132 {
2133  bool found;
2134 
2135  Assert(LWLockHeldByMe(SerializablePredicateListLock));
2136 
2137  if (!lockheld)
2142  HASH_ENTER, &found);
2143  Assert(!found);
2144  if (!lockheld)
2146 }

References Assert(), HASH_ENTER, hash_search_with_hash_value(), LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), PredicateLockTargetHash, ScratchPartitionLock, ScratchTargetTag, and ScratchTargetTagHash.

Referenced by DropAllPredicateLocksFromTable(), and TransferPredicateLocksToNewTarget().

◆ RWConflictExists()

static bool RWConflictExists ( const SERIALIZABLEXACT reader,
const SERIALIZABLEXACT writer 
)
static

Definition at line 611 of file predicate.c.

612 {
613  dlist_iter iter;
614 
615  Assert(reader != writer);
616 
617  /* Check the ends of the purported conflict first. */
618  if (SxactIsDoomed(reader)
619  || SxactIsDoomed(writer)
620  || dlist_is_empty(&reader->outConflicts)
621  || dlist_is_empty(&writer->inConflicts))
622  return false;
623 
624  /*
625  * A conflict is possible; walk the list to find out.
626  *
627  * The unconstify is needed as we have no const version of
628  * dlist_foreach().
629  */
630  dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->outConflicts)
631  {
632  RWConflict conflict =
633  dlist_container(RWConflictData, outLink, iter.cur);
634 
635  if (conflict->sxactIn == writer)
636  return true;
637  }
638 
639  /* No conflict found. */
640  return false;
641 }

References Assert(), dlist_iter::cur, dlist_container, dlist_foreach, dlist_is_empty(), SERIALIZABLEXACT::inConflicts, SERIALIZABLEXACT::outConflicts, RWConflictData::sxactIn, SxactIsDoomed, and unconstify.

Referenced by CheckForSerializableConflictOut(), CheckTableForSerializableConflictIn(), CheckTargetForConflictsIn(), and SetRWConflict().

◆ SerialAdd()

static void SerialAdd ( TransactionId  xid,
SerCommitSeqNo  minConflictCommitSeqNo 
)
static

Definition at line 850 of file predicate.c.

851 {
852  TransactionId tailXid;
853  int64 targetPage;
854  int slotno;
855  int64 firstZeroPage;
856  bool isNewPage;
857 
859 
860  targetPage = SerialPage(xid);
861 
862  /*
863  * In this routine, we must hold both SerialControlLock and SerialSLRULock
864  * simultaneously while making the SLRU data catch up with the new state
865  * that we determine.
866  */
867  LWLockAcquire(SerialControlLock, LW_EXCLUSIVE);
868 
869  /*
870  * If no serializable transactions are active, there shouldn't be anything
871  * to push out to the SLRU. Hitting this assert would mean there's
872  * something wrong with the earlier cleanup logic.
873  */
874  tailXid = serialControl->tailXid;
875  Assert(TransactionIdIsValid(tailXid));
876 
877  /*
878  * If the SLRU is currently unused, zero out the whole active region from
879  * tailXid to headXid before taking it into use. Otherwise zero out only
880  * any new pages that enter the tailXid-headXid range as we advance
881  * headXid.
882  */
883  if (serialControl->headPage < 0)
884  {
885  firstZeroPage = SerialPage(tailXid);
886  isNewPage = true;
887  }
888  else
889  {
890  firstZeroPage = SerialNextPage(serialControl->headPage);
892  targetPage);
893  }
894 
897  serialControl->headXid = xid;
898  if (isNewPage)
899  serialControl->headPage = targetPage;
900 
901  LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
902 
903  if (isNewPage)
904  {
905  /* Initialize intervening pages. */
906  while (firstZeroPage != targetPage)
907  {
908  (void) SimpleLruZeroPage(SerialSlruCtl, firstZeroPage);
909  firstZeroPage = SerialNextPage(firstZeroPage);
910  }
911  slotno = SimpleLruZeroPage(SerialSlruCtl, targetPage);
912  }
913  else
914  slotno = SimpleLruReadPage(SerialSlruCtl, targetPage, true, xid);
915 
916  SerialValue(slotno, xid) = minConflictCommitSeqNo;
917  SerialSlruCtl->shared->page_dirty[slotno] = true;
918 
919  LWLockRelease(SerialSLRULock);
920  LWLockRelease(SerialControlLock);
921 }
uint32 TransactionId
Definition: c.h:641
#define SerialNextPage(page)
Definition: predicate.c:338
#define SerialValue(slotno, xid)
Definition: predicate.c:340
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition: slru.c:430
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:308
TransactionId headXid
Definition: predicate.c:349

References Assert(), SerialControlData::headPage, SerialControlData::headXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), serialControl, SerialNextPage, SerialPage, SerialPagePrecedesLogically(), SerialSlruCtl, SerialValue, SimpleLruReadPage(), SimpleLruZeroPage(), SerialControlData::tailXid, TransactionIdFollows(), and TransactionIdIsValid.

Referenced by SummarizeOldestCommittedSxact().

◆ SerialGetMinConflictCommitSeqNo()

static SerCommitSeqNo SerialGetMinConflictCommitSeqNo ( TransactionId  xid)
static

Definition at line 929 of file predicate.c.

930 {
931  TransactionId headXid;
932  TransactionId tailXid;
934  int slotno;
935 
937 
938  LWLockAcquire(SerialControlLock, LW_SHARED);
939  headXid = serialControl->headXid;
940  tailXid = serialControl->tailXid;
941  LWLockRelease(SerialControlLock);
942 
943  if (!TransactionIdIsValid(headXid))
944  return 0;
945 
946  Assert(TransactionIdIsValid(tailXid));
947 
948  if (TransactionIdPrecedes(xid, tailXid)
949  || TransactionIdFollows(xid, headXid))
950  return 0;
951 
952  /*
953  * The following function must be called without holding SerialSLRULock,
954  * but will return with that lock held, which must then be released.
955  */
957  SerialPage(xid), xid);
958  val = SerialValue(slotno, xid);
959  LWLockRelease(SerialSLRULock);
960  return val;
961 }
long val
Definition: informix.c:664
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:530

References Assert(), SerialControlData::headXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), serialControl, SerialPage, SerialSlruCtl, SerialValue, SimpleLruReadPage_ReadOnly(), SerialControlData::tailXid, TransactionIdFollows(), TransactionIdIsValid, TransactionIdPrecedes(), and val.

Referenced by CheckForSerializableConflictOut().

◆ SerialInit()

static void SerialInit ( void  )
static

Definition at line 807 of file predicate.c.

808 {
809  bool found;
810 
811  /*
812  * Set up SLRU management of the pg_serial data.
813  */
815  SimpleLruInit(SerialSlruCtl, "Serial",
816  NUM_SERIAL_BUFFERS, 0, SerialSLRULock, "pg_serial",
818  false);
819 #ifdef USE_ASSERT_CHECKING
820  SerialPagePrecedesLogicallyUnitTests();
821 #endif
823 
824  /*
825  * Create or attach to the SerialControl structure.
826  */
828  ShmemInitStruct("SerialControlData", sizeof(SerialControlData), &found);
829 
830  Assert(found == IsUnderPostmaster);
831  if (!found)
832  {
833  /*
834  * Set control information to reflect empty SLRU.
835  */
836  LWLockAcquire(SerialControlLock, LW_EXCLUSIVE);
837  serialControl->headPage = -1;
840  LWLockRelease(SerialControlLock);
841  }
842 }
@ LWTRANCHE_SERIAL_BUFFER
Definition: lwlock.h:187
struct SerialControlData * SerialControl
Definition: predicate.c:353
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
Definition: slru.c:215
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:168
@ SYNC_HANDLER_NONE
Definition: sync.h:42

References Assert(), SerialControlData::headPage, SerialControlData::headXid, InvalidTransactionId, IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), LWTRANCHE_SERIAL_BUFFER, NUM_SERIAL_BUFFERS, SERIAL_ENTRIESPERPAGE, serialControl, SerialPagePrecedesLogically(), SerialSlruCtl, ShmemInitStruct(), SimpleLruInit(), SlruPagePrecedesUnitTests, SYNC_HANDLER_NONE, and SerialControlData::tailXid.

Referenced by InitPredicateLocks().

◆ SerializationNeededForRead()

static bool SerializationNeededForRead ( Relation  relation,
Snapshot  snapshot 
)
inlinestatic

Definition at line 517 of file predicate.c.

518 {
519  /* Nothing to do if this is not a serializable transaction */
521  return false;
522 
523  /*
524  * Don't acquire locks or conflict when scanning with a special snapshot.
525  * This excludes things like CLUSTER and REINDEX. They use the wholesale
526  * functions TransferPredicateLocksToHeapRelation() and
527  * CheckTableForSerializableConflictIn() to participate in serialization,
528  * but the scans involved don't need serialization.
529  */
530  if (!IsMVCCSnapshot(snapshot))
531  return false;
532 
533  /*
534  * Check if we have just become "RO-safe". If we have, immediately release
535  * all locks as they're not needed anymore. This also resets
536  * MySerializableXact, so that subsequent calls to this function can exit
537  * quickly.
538  *
539  * A transaction is flagged as RO_SAFE if all concurrent R/W transactions
540  * commit without having conflicts out to an earlier snapshot, thus
541  * ensuring that no conflicts are possible for this transaction.
542  */
544  {
545  ReleasePredicateLocks(false, true);
546  return false;
547  }
548 
549  /* Check if the relation doesn't participate in predicate locking */
550  if (!PredicateLockingNeededForRelation(relation))
551  return false;
552 
553  return true; /* no excuse to skip predicate locking */
554 }
#define IsMVCCSnapshot(snapshot)
Definition: snapmgr.h:62

References InvalidSerializableXact, IsMVCCSnapshot, MySerializableXact, PredicateLockingNeededForRelation(), ReleasePredicateLocks(), and SxactIsROSafe.

Referenced by CheckForSerializableConflictOut(), CheckForSerializableConflictOutNeeded(), PredicateLockPage(), PredicateLockRelation(), and PredicateLockTID().

◆ SerializationNeededForWrite()

static bool SerializationNeededForWrite ( Relation  relation)
inlinestatic

Definition at line 561 of file predicate.c.

562 {
563  /* Nothing to do if this is not a serializable transaction */
565  return false;
566 
567  /* Check if the relation doesn't participate in predicate locking */
568  if (!PredicateLockingNeededForRelation(relation))
569  return false;
570 
571  return true; /* no excuse to skip predicate locking */
572 }

References InvalidSerializableXact, MySerializableXact, and PredicateLockingNeededForRelation().

Referenced by CheckForSerializableConflictIn(), and CheckTableForSerializableConflictIn().

◆ SerialPagePrecedesLogically()

static bool SerialPagePrecedesLogically ( int64  page1,
int64  page2 
)
static

Definition at line 732 of file predicate.c.

733 {
734  TransactionId xid1;
735  TransactionId xid2;
736 
737  xid1 = ((TransactionId) page1) * SERIAL_ENTRIESPERPAGE;
738  xid1 += FirstNormalTransactionId + 1;
739  xid2 = ((TransactionId) page2) * SERIAL_ENTRIESPERPAGE;
740  xid2 += FirstNormalTransactionId + 1;
741 
742  return (TransactionIdPrecedes(xid1, xid2) &&
743  TransactionIdPrecedes(xid1, xid2 + SERIAL_ENTRIESPERPAGE - 1));
744 }
#define FirstNormalTransactionId
Definition: transam.h:34

References FirstNormalTransactionId, SERIAL_ENTRIESPERPAGE, and TransactionIdPrecedes().

Referenced by CheckPointPredicate(), SerialAdd(), and SerialInit().

◆ SerialSetActiveSerXmin()

static void SerialSetActiveSerXmin ( TransactionId  xid)
static

Definition at line 970 of file predicate.c.

971 {
972  LWLockAcquire(SerialControlLock, LW_EXCLUSIVE);
973 
974  /*
975  * When no sxacts are active, nothing overlaps, set the xid values to
976  * invalid to show that there are no valid entries. Don't clear headPage,
977  * though. A new xmin might still land on that page, and we don't want to
978  * repeatedly zero out the same page.
979  */
980  if (!TransactionIdIsValid(xid))
981  {
984  LWLockRelease(SerialControlLock);
985  return;
986  }
987 
988  /*
989  * When we're recovering prepared transactions, the global xmin might move
990  * backwards depending on the order they're recovered. Normally that's not
991  * OK, but during recovery no serializable transactions will commit, so
992  * the SLRU is empty and we can get away with it.
993  */
994  if (RecoveryInProgress())
995  {