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 "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  OldSerXidControlData
 

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)   (!SHMQueueIsDetached(&((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 OldSerXidSlruCtl   (&OldSerXidSlruCtlData)
 
#define OLDSERXID_PAGESIZE   BLCKSZ
 
#define OLDSERXID_ENTRYSIZE   sizeof(SerCommitSeqNo)
 
#define OLDSERXID_ENTRIESPERPAGE   (OLDSERXID_PAGESIZE / OLDSERXID_ENTRYSIZE)
 
#define OLDSERXID_MAX_PAGE   (MaxTransactionId / OLDSERXID_ENTRIESPERPAGE)
 
#define OldSerXidNextPage(page)   (((page) >= OLDSERXID_MAX_PAGE) ? 0 : (page) + 1)
 
#define OldSerXidValue(slotno, xid)
 
#define OldSerXidPage(xid)   (((uint32) (xid)) / OLDSERXID_ENTRIESPERPAGE)
 

Typedefs

typedef struct OldSerXidControlData OldSerXidControlData
 
typedef struct OldSerXidControlDataOldSerXidControl
 

Functions

static SERIALIZABLEXACTCreatePredXact (void)
 
static void ReleasePredXact (SERIALIZABLEXACT *sxact)
 
static SERIALIZABLEXACTFirstPredXact (void)
 
static SERIALIZABLEXACTNextPredXact (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 OldSerXidPagePrecedesLogically (int p, int q)
 
static void OldSerXidInit (void)
 
static void OldSerXidAdd (TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
 
static SerCommitSeqNo OldSerXidGetMinConflictCommitSeqNo (TransactionId xid)
 
static void OldSerXidSetActiveSerXmin (TransactionId xid)
 
static uint32 predicatelock_hash (const void *key, Size keysize)
 
static void SummarizeOldestCommittedSxact (void)
 
static Snapshot GetSafeSnapshot (Snapshot snapshot)
 
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 OldSerXidSlruCtlData
 
static OldSerXidControl oldSerXidControl
 
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 SHM_QUEUEFinishedSerializableTransactions
 
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 259 of file predicate.c.

Referenced by InitPredicateLocks(), and PredicateLockShmemSize().

◆ OLDSERXID_ENTRIESPERPAGE

#define OLDSERXID_ENTRIESPERPAGE   (OLDSERXID_PAGESIZE / OLDSERXID_ENTRYSIZE)

Definition at line 325 of file predicate.c.

◆ OLDSERXID_ENTRYSIZE

#define OLDSERXID_ENTRYSIZE   sizeof(SerCommitSeqNo)

Definition at line 324 of file predicate.c.

◆ OLDSERXID_MAX_PAGE

#define OLDSERXID_MAX_PAGE   (MaxTransactionId / OLDSERXID_ENTRIESPERPAGE)

Definition at line 330 of file predicate.c.

Referenced by OldSerXidPagePrecedesLogically().

◆ OLDSERXID_PAGESIZE

#define OLDSERXID_PAGESIZE   BLCKSZ

Definition at line 323 of file predicate.c.

◆ OldSerXidNextPage

#define OldSerXidNextPage (   page)    (((page) >= OLDSERXID_MAX_PAGE) ? 0 : (page) + 1)

Definition at line 332 of file predicate.c.

Referenced by OldSerXidAdd().

◆ OldSerXidPage

#define OldSerXidPage (   xid)    (((uint32) (xid)) / OLDSERXID_ENTRIESPERPAGE)

◆ OldSerXidSlruCtl

#define OldSerXidSlruCtl   (&OldSerXidSlruCtlData)

◆ OldSerXidValue

#define OldSerXidValue (   slotno,
  xid 
)
Value:
(OldSerXidSlruCtl->shared->page_buffer[slotno] + \
#define OLDSERXID_ENTRYSIZE
Definition: predicate.c:324
#define OldSerXidSlruCtl
Definition: predicate.c:321
#define OLDSERXID_ENTRIESPERPAGE
Definition: predicate.c:325
unsigned int uint32
Definition: c.h:367
uint64 SerCommitSeqNo

Definition at line 334 of file predicate.c.

Referenced by OldSerXidAdd(), and OldSerXidGetMinConflictCommitSeqNo().

◆ PredicateLockHashCodeFromTargetHashCode

#define PredicateLockHashCodeFromTargetHashCode (   predicatelocktag,
  targethash 
)

◆ PredicateLockHashPartition

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

Definition at line 251 of file predicate.c.

◆ PredicateLockHashPartitionLock

#define PredicateLockHashPartitionLock (   hashcode)

◆ PredicateLockHashPartitionLockByIndex

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

◆ PredicateLockTargetTagHashCode

◆ SxactHasConflictOut

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

◆ SxactHasSummaryConflictIn

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

◆ SxactHasSummaryConflictOut

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

◆ SxactIsCommitted

◆ SxactIsDeferrableWaiting

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

Definition at line 285 of file predicate.c.

Referenced by GetSafeSnapshotBlockingPids(), and ReleasePredicateLocks().

◆ SxactIsDoomed

◆ SxactIsOnFinishedList

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

Definition at line 262 of file predicate.c.

Referenced by ReleaseOneSerializableXact(), and ReleasePredicateLocks().

◆ SxactIsPartiallyReleased

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

Definition at line 288 of file predicate.c.

Referenced by PreCommit_CheckForSerializationFailure(), and ReleasePredicateLocks().

◆ SxactIsPrepared

◆ SxactIsReadOnly

◆ SxactIsRolledBack

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

◆ SxactIsROSafe

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

◆ SxactIsROUnsafe

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

Definition at line 287 of file predicate.c.

Referenced by GetSafeSnapshot(), and ReleasePredicateLocks().

◆ 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 GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
#define GET_PREDICATELOCKTARGETTAG_PAGE(locktag)
#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag)
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
#define InvalidOffsetNumber
Definition: off.h:26
#define InvalidBlockNumber
Definition: block.h:33

Definition at line 228 of file predicate.c.

Referenced by DeleteChildTargetLocks().

Typedef Documentation

◆ OldSerXidControl

Definition at line 347 of file predicate.c.

◆ OldSerXidControlData

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4853 of file predicate.c.

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

Referenced by PrepareTransaction().

4854 {
4855  PREDICATELOCK *predlock;
4856  SERIALIZABLEXACT *sxact;
4857  TwoPhasePredicateRecord record;
4858  TwoPhasePredicateXactRecord *xactRecord;
4859  TwoPhasePredicateLockRecord *lockRecord;
4860 
4861  sxact = MySerializableXact;
4862  xactRecord = &(record.data.xactRecord);
4863  lockRecord = &(record.data.lockRecord);
4864 
4866  return;
4867 
4868  /* Generate an xact record for our SERIALIZABLEXACT */
4870  xactRecord->xmin = MySerializableXact->xmin;
4871  xactRecord->flags = MySerializableXact->flags;
4872 
4873  /*
4874  * Note that we don't include the list of conflicts in our out in the
4875  * statefile, because new conflicts can be added even after the
4876  * transaction prepares. We'll just make a conservative assumption during
4877  * recovery instead.
4878  */
4879 
4881  &record, sizeof(record));
4882 
4883  /*
4884  * Generate a lock record for each lock.
4885  *
4886  * To do this, we need to walk the predicate lock list in our sxact rather
4887  * than using the local predicate lock table because the latter is not
4888  * guaranteed to be accurate.
4889  */
4890  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
4891 
4892  /*
4893  * No need to take sxact->predicateLockListLock in parallel mode because
4894  * there cannot be any parallel workers running while we are preparing a
4895  * transaction.
4896  */
4898 
4899  predlock = (PREDICATELOCK *)
4900  SHMQueueNext(&(sxact->predicateLocks),
4901  &(sxact->predicateLocks),
4902  offsetof(PREDICATELOCK, xactLink));
4903 
4904  while (predlock != NULL)
4905  {
4907  lockRecord->target = predlock->tag.myTarget->tag;
4908 
4910  &record, sizeof(record));
4911 
4912  predlock = (PREDICATELOCK *)
4913  SHMQueueNext(&(sxact->predicateLocks),
4914  &(predlock->xactLink),
4915  offsetof(PREDICATELOCK, xactLink));
4916  }
4917 
4918  LWLockRelease(SerializablePredicateLockListLock);
4919 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
union TwoPhasePredicateRecord::@108 data
TwoPhasePredicateRecordType type
PREDICATELOCKTARGETTAG target
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1187
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
#define TWOPHASE_RM_PREDICATELOCK_ID
Definition: twophase_rmgr.h:28
TwoPhasePredicateXactRecord xactRecord
#define InvalidSerializableXact
#define IsParallelWorker()
Definition: parallel.h:61
bool ParallelContextActive(void)
Definition: parallel.c:978
PREDICATELOCKTAG tag
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:738
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
TwoPhasePredicateLockRecord lockRecord
#define offsetof(type, field)
Definition: c.h:661
PREDICATELOCKTARGET * myTarget

◆ AttachSerializableXact()

void AttachSerializableXact ( SerializableXactHandle  handle)

Definition at line 5123 of file predicate.c.

References Assert, CreateLocalPredicateLockHash(), and InvalidSerializableXact.

Referenced by ParallelWorkerMain().

5124 {
5125 
5127 
5128  MySerializableXact = (SERIALIZABLEXACT *) handle;
5131 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
#define InvalidSerializableXact
#define Assert(condition)
Definition: c.h:738
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1852

◆ CheckAndPromotePredicateLockRequest()

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2249 of file predicate.c.

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

Referenced by PredicateLockAcquire().

2250 {
2251  PREDICATELOCKTARGETTAG targettag,
2252  nexttag,
2253  promotiontag;
2254  LOCALPREDICATELOCK *parentlock;
2255  bool found,
2256  promote;
2257 
2258  promote = false;
2259 
2260  targettag = *reqtag;
2261 
2262  /* check parents iteratively */
2263  while (GetParentPredicateLockTag(&targettag, &nexttag))
2264  {
2265  targettag = nexttag;
2267  &targettag,
2268  HASH_ENTER,
2269  &found);
2270  if (!found)
2271  {
2272  parentlock->held = false;
2273  parentlock->childLocks = 1;
2274  }
2275  else
2276  parentlock->childLocks++;
2277 
2278  if (parentlock->childLocks >
2279  MaxPredicateChildLocks(&targettag))
2280  {
2281  /*
2282  * We should promote to this parent lock. Continue to check its
2283  * ancestors, however, both to get their child counts right and to
2284  * check whether we should just go ahead and promote to one of
2285  * them.
2286  */
2287  promotiontag = targettag;
2288  promote = true;
2289  }
2290  }
2291 
2292  if (promote)
2293  {
2294  /* acquire coarsest ancestor eligible for promotion */
2295  PredicateLockAcquire(&promotiontag);
2296  return true;
2297  }
2298  else
2299  return false;
2300 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:908
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2441
static int MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag)
Definition: predicate.c:2212
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:1985
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409

◆ CheckForSerializableConflictIn()

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

Definition at line 4374 of file predicate.c.

References CheckTargetForConflictsIn(), RelFileNode::dbNode, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, InvalidBlockNumber, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, MyXactDidWrite, RelationData::rd_id, RelationData::rd_node, 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().

4375 {
4376  PREDICATELOCKTARGETTAG targettag;
4377 
4378  if (!SerializationNeededForWrite(relation))
4379  return;
4380 
4381  /* Check if someone else has already decided that we need to die */
4383  ereport(ERROR,
4384  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4385  errmsg("could not serialize access due to read/write dependencies among transactions"),
4386  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4387  errhint("The transaction might succeed if retried.")));
4388 
4389  /*
4390  * We're doing a write which might cause rw-conflicts now or later.
4391  * Memorize that fact.
4392  */
4393  MyXactDidWrite = true;
4394 
4395  /*
4396  * It is important that we check for locks from the finest granularity to
4397  * the coarsest granularity, so that granularity promotion doesn't cause
4398  * us to miss a lock. The new (coarser) lock will be acquired before the
4399  * old (finer) locks are released.
4400  *
4401  * It is not possible to take and hold a lock across the checks for all
4402  * granularities because each target could be in a separate partition.
4403  */
4404  if (tid != NULL)
4405  {
4407  relation->rd_node.dbNode,
4408  relation->rd_id,
4411  CheckTargetForConflictsIn(&targettag);
4412  }
4413 
4414  if (blkno != InvalidBlockNumber)
4415  {
4417  relation->rd_node.dbNode,
4418  relation->rd_id,
4419  blkno);
4420  CheckTargetForConflictsIn(&targettag);
4421  }
4422 
4424  relation->rd_node.dbNode,
4425  relation->rd_id);
4426  CheckTargetForConflictsIn(&targettag);
4427 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
int errhint(const char *fmt,...)
Definition: elog.c:1071
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4192
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
int errcode(int sqlerrcode)
Definition: elog.c:610
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:558
#define SET_PREDICATELOCKTARGETTAG_TUPLE(locktag, dboid, reloid, blocknum, offnum)
#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag, dboid, reloid)
int errdetail_internal(const char *fmt,...)
Definition: elog.c:984
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define ERROR
Definition: elog.h:43
Oid rd_id
Definition: rel.h:111
#define ereport(elevel,...)
Definition: elog.h:144
RelFileNode rd_node
Definition: rel.h:55
#define InvalidBlockNumber
Definition: block.h:33
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
int errmsg(const char *fmt,...)
Definition: elog.c:824
static bool MyXactDidWrite
Definition: predicate.c:417
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98

◆ CheckForSerializableConflictOut()

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

Definition at line 4049 of file predicate.c.

References Assert, SERIALIZABLEXACT::earliestOutConflictCommit, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, FlagRWConflict(), SERIALIZABLEXACT::flags, GetTopTransactionIdIfAny(), HASH_FIND, hash_search(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SERIALIZABLEXID::myXact, OldSerXidGetMinConflictCommitSeqNo(), RWConflictExists(), SERIALIZABLEXACT::SeqNo, SerializationNeededForRead(), SHMQueueEmpty(), 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().

4050 {
4051  SERIALIZABLEXIDTAG sxidtag;
4052  SERIALIZABLEXID *sxid;
4053  SERIALIZABLEXACT *sxact;
4054 
4055  if (!SerializationNeededForRead(relation, snapshot))
4056  return;
4057 
4058  /* Check if someone else has already decided that we need to die */
4060  {
4061  ereport(ERROR,
4062  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4063  errmsg("could not serialize access due to read/write dependencies among transactions"),
4064  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4065  errhint("The transaction might succeed if retried.")));
4066  }
4068 
4070  return;
4071 
4072  /*
4073  * Find sxact or summarized info for the top level xid.
4074  */
4075  sxidtag.xid = xid;
4076  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4077  sxid = (SERIALIZABLEXID *)
4078  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4079  if (!sxid)
4080  {
4081  /*
4082  * Transaction not found in "normal" SSI structures. Check whether it
4083  * got pushed out to SLRU storage for "old committed" transactions.
4084  */
4085  SerCommitSeqNo conflictCommitSeqNo;
4086 
4087  conflictCommitSeqNo = OldSerXidGetMinConflictCommitSeqNo(xid);
4088  if (conflictCommitSeqNo != 0)
4089  {
4090  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4092  || conflictCommitSeqNo
4094  ereport(ERROR,
4095  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4096  errmsg("could not serialize access due to read/write dependencies among transactions"),
4097  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4098  errhint("The transaction might succeed if retried.")));
4099 
4102  ereport(ERROR,
4103  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4104  errmsg("could not serialize access due to read/write dependencies among transactions"),
4105  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4106  errhint("The transaction might succeed if retried.")));
4107 
4109  }
4110 
4111  /* It's not serializable or otherwise not important. */
4112  LWLockRelease(SerializableXactHashLock);
4113  return;
4114  }
4115  sxact = sxid->myXact;
4116  Assert(TransactionIdEquals(sxact->topXid, xid));
4117  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4118  {
4119  /* Can't conflict with ourself or a transaction that will roll back. */
4120  LWLockRelease(SerializableXactHashLock);
4121  return;
4122  }
4123 
4124  /*
4125  * We have a conflict out to a transaction which has a conflict out to a
4126  * summarized transaction. That summarized transaction must have
4127  * committed first, and we can't tell when it committed in relation to our
4128  * snapshot acquisition, so something needs to be canceled.
4129  */
4130  if (SxactHasSummaryConflictOut(sxact))
4131  {
4132  if (!SxactIsPrepared(sxact))
4133  {
4134  sxact->flags |= SXACT_FLAG_DOOMED;
4135  LWLockRelease(SerializableXactHashLock);
4136  return;
4137  }
4138  else
4139  {
4140  LWLockRelease(SerializableXactHashLock);
4141  ereport(ERROR,
4142  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4143  errmsg("could not serialize access due to read/write dependencies among transactions"),
4144  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4145  errhint("The transaction might succeed if retried.")));
4146  }
4147  }
4148 
4149  /*
4150  * If this is a read-only transaction and the writing transaction has
4151  * committed, and it doesn't have a rw-conflict to a transaction which
4152  * committed before it, no conflict.
4153  */
4155  && SxactIsCommitted(sxact)
4156  && !SxactHasSummaryConflictOut(sxact)
4157  && (!SxactHasConflictOut(sxact)
4159  {
4160  /* Read-only transaction will appear to run first. No conflict. */
4161  LWLockRelease(SerializableXactHashLock);
4162  return;
4163  }
4164 
4165  if (!XidIsConcurrent(xid))
4166  {
4167  /* This write was already in our snapshot; no conflict. */
4168  LWLockRelease(SerializableXactHashLock);
4169  return;
4170  }
4171 
4173  {
4174  /* We don't want duplicate conflict records in the list. */
4175  LWLockRelease(SerializableXactHashLock);
4176  return;
4177  }
4178 
4179  /*
4180  * Flag the conflict. But first, if this conflict creates a dangerous
4181  * structure, ereport an error.
4182  */
4184  LWLockRelease(SerializableXactHashLock);
4185 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:653
int errhint(const char *fmt,...)
Definition: elog.c:1071
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4549
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:277
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:3994
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
int errcode(int sqlerrcode)
Definition: elog.c:610
static HTAB * SerializableXidHash
Definition: predicate.c:391
SERIALIZABLEXACT * myXact
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:908
#define SxactIsPrepared(sxact)
Definition: predicate.c:273
int errdetail_internal(const char *fmt,...)
Definition: elog.c:984
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define ERROR
Definition: elog.h:43
SerCommitSeqNo lastCommitBeforeSnapshot
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:409
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:278
#define InvalidSerCommitSeqNo
bool SHMQueueEmpty(const SHM_QUEUE *queue)
Definition: shmqueue.c:180
SerCommitSeqNo earliestOutConflictCommit
#define ereport(elevel,...)
Definition: elog.h:144
static SerCommitSeqNo OldSerXidGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:923
uint64 SerCommitSeqNo
#define SXACT_FLAG_DOOMED
#define SxactHasConflictOut(sxact)
Definition: predicate.c:284
#define Assert(condition)
Definition: c.h:738
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:514
int errmsg(const char *fmt,...)
Definition: elog.c:824
union SERIALIZABLEXACT::@107 SeqNo
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define SxactIsCommitted(sxact)
Definition: predicate.c:272

◆ CheckForSerializableConflictOutNeeded()

bool CheckForSerializableConflictOutNeeded ( Relation  relation,
Snapshot  snapshot 
)

Definition at line 4020 of file predicate.c.

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

Referenced by HeapCheckForSerializableConflictOut().

4021 {
4022  if (!SerializationNeededForRead(relation, snapshot))
4023  return false;
4024 
4025  /* Check if someone else has already decided that we need to die */
4027  {
4028  ereport(ERROR,
4029  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4030  errmsg("could not serialize access due to read/write dependencies among transactions"),
4031  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4032  errhint("The transaction might succeed if retried.")));
4033  }
4034 
4035  return true;
4036 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
int errhint(const char *fmt,...)
Definition: elog.c:1071
int errcode(int sqlerrcode)
Definition: elog.c:610
int errdetail_internal(const char *fmt,...)
Definition: elog.c:984
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define ERROR
Definition: elog.h:43
#define ereport(elevel,...)
Definition: elog.h:144
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:514
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 1015 of file predicate.c.

References OldSerXidControlData::headPage, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), OldSerXidPage, OldSerXidSlruCtl, SimpleLruFlush(), SimpleLruTruncate(), OldSerXidControlData::tailXid, and TransactionIdIsValid.

Referenced by CheckPointGuts().

1016 {
1017  int tailPage;
1018 
1019  LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);
1020 
1021  /* Exit quickly if the SLRU is currently not in use. */
1022  if (oldSerXidControl->headPage < 0)
1023  {
1024  LWLockRelease(OldSerXidLock);
1025  return;
1026  }
1027 
1029  {
1030  /* We can truncate the SLRU up to the page containing tailXid */
1031  tailPage = OldSerXidPage(oldSerXidControl->tailXid);
1032  }
1033  else
1034  {
1035  /*
1036  * The SLRU is no longer needed. Truncate to head before we set head
1037  * invalid.
1038  *
1039  * XXX: It's possible that the SLRU is not needed again until XID
1040  * wrap-around has happened, so that the segment containing headPage
1041  * that we leave behind will appear to be new again. In that case it
1042  * won't be removed until XID horizon advances enough to make it
1043  * current again.
1044  */
1045  tailPage = oldSerXidControl->headPage;
1046  oldSerXidControl->headPage = -1;
1047  }
1048 
1049  LWLockRelease(OldSerXidLock);
1050 
1051  /* Truncate away pages that are no longer required */
1053 
1054  /*
1055  * Flush dirty SLRU pages to disk
1056  *
1057  * This is not actually necessary from a correctness point of view. We do
1058  * it merely as a debugging aid.
1059  *
1060  * We're doing this after the truncation to avoid writing pages right
1061  * before deleting the file in which they sit, which would be completely
1062  * pointless.
1063  */
1065 }
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1208
#define OldSerXidPage(xid)
Definition: predicate.c:338
#define OldSerXidSlruCtl
Definition: predicate.c:321
void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1140
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
static OldSerXidControl oldSerXidControl
Definition: predicate.c:349
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId tailXid
Definition: predicate.c:344

◆ CheckTableForSerializableConflictIn()

void CheckTableForSerializableConflictIn ( Relation  relation)

Definition at line 4457 of file predicate.c.

References Assert, RelFileNode::dbNode, FlagRWConflict(), GET_PREDICATELOCKTARGETTAG_DB, GET_PREDICATELOCKTARGETTAG_RELATION, hash_seq_init(), hash_seq_search(), i, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myXact, MyXactDidWrite, NUM_PREDICATELOCK_PARTITIONS, offsetof, PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::predicateLocks, RelationData::rd_id, RelationData::rd_index, RelationData::rd_node, RWConflictExists(), SerializationNeededForWrite(), SHMQueueNext(), PredXactListData::SxactGlobalXmin, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, and TransactionIdIsValid.

Referenced by ExecuteTruncateGuts(), and heap_drop_with_catalog().

4458 {
4459  HASH_SEQ_STATUS seqstat;
4460  PREDICATELOCKTARGET *target;
4461  Oid dbId;
4462  Oid heapId;
4463  int i;
4464 
4465  /*
4466  * Bail out quickly if there are no serializable transactions running.
4467  * It's safe to check this without taking locks because the caller is
4468  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4469  * would matter here can be acquired while that is held.
4470  */
4472  return;
4473 
4474  if (!SerializationNeededForWrite(relation))
4475  return;
4476 
4477  /*
4478  * We're doing a write which might cause rw-conflicts now or later.
4479  * Memorize that fact.
4480  */
4481  MyXactDidWrite = true;
4482 
4483  Assert(relation->rd_index == NULL); /* not an index relation */
4484 
4485  dbId = relation->rd_node.dbNode;
4486  heapId = relation->rd_id;
4487 
4488  LWLockAcquire(SerializablePredicateLockListLock, LW_EXCLUSIVE);
4489  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4491  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4492 
4493  /* Scan through target list */
4495 
4496  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4497  {
4498  PREDICATELOCK *predlock;
4499 
4500  /*
4501  * Check whether this is a target which needs attention.
4502  */
4503  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4504  continue; /* wrong relation id */
4505  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4506  continue; /* wrong database id */
4507 
4508  /*
4509  * Loop through locks for this target and flag conflicts.
4510  */
4511  predlock = (PREDICATELOCK *)
4512  SHMQueueNext(&(target->predicateLocks),
4513  &(target->predicateLocks),
4514  offsetof(PREDICATELOCK, targetLink));
4515  while (predlock)
4516  {
4517  PREDICATELOCK *nextpredlock;
4518 
4519  nextpredlock = (PREDICATELOCK *)
4520  SHMQueueNext(&(target->predicateLocks),
4521  &(predlock->targetLink),
4522  offsetof(PREDICATELOCK, targetLink));
4523 
4524  if (predlock->tag.myXact != MySerializableXact
4526  {
4528  }
4529 
4530  predlock = nextpredlock;
4531  }
4532  }
4533 
4534  /* Release locks in reverse order */
4535  LWLockRelease(SerializableXactHashLock);
4536  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4538  LWLockRelease(SerializablePredicateLockListLock);
4539 }
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:653
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4549
static PredXactList PredXact
Definition: predicate.c:379
TransactionId SxactGlobalXmin
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:558
unsigned int Oid
Definition: postgres_ext.h:31
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
Form_pg_index rd_index
Definition: rel.h:174
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
Oid rd_id
Definition: rel.h:111
PREDICATELOCKTAG tag
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
RelFileNode rd_node
Definition: rel.h:55
#define Assert(condition)
Definition: c.h:738
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1391
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1381
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:256
int i
SERIALIZABLEXACT * myXact
static bool MyXactDidWrite
Definition: predicate.c:417
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define offsetof(type, field)
Definition: c.h:661
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:121

◆ CheckTargetForConflictsIn()

static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag)
static

Definition at line 4192 of file predicate.c.

References Assert, DecrementParentLocks(), SERIALIZABLEXACT::finishedBefore, FlagRWConflict(), GET_PREDICATELOCKTARGETTAG_OFFSET, GetTransactionSnapshot(), HASH_FIND, HASH_REMOVE, hash_search_with_hash_value(), InvalidSerializableXact, IsInParallelMode(), IsSubTransaction(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myXact, offsetof, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLockListLock, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetTagHashCode, RemoveTargetIfNoLongerUsed(), RWConflictExists(), SHMQueueDelete(), SHMQueueNext(), SxactIsCommitted, SxactIsDoomed, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdPrecedes(), and PREDICATELOCK::xactLink.

Referenced by CheckForSerializableConflictIn().

4193 {
4194  uint32 targettaghash;
4195  LWLock *partitionLock;
4196  PREDICATELOCKTARGET *target;
4197  PREDICATELOCK *predlock;
4198  PREDICATELOCK *mypredlock = NULL;
4199  PREDICATELOCKTAG mypredlocktag;
4200 
4202 
4203  /*
4204  * The same hash and LW lock apply to the lock target and the lock itself.
4205  */
4206  targettaghash = PredicateLockTargetTagHashCode(targettag);
4207  partitionLock = PredicateLockHashPartitionLock(targettaghash);
4208  LWLockAcquire(partitionLock, LW_SHARED);
4209  target = (PREDICATELOCKTARGET *)
4211  targettag, targettaghash,
4212  HASH_FIND, NULL);
4213  if (!target)
4214  {
4215  /* Nothing has this target locked; we're done here. */
4216  LWLockRelease(partitionLock);
4217  return;
4218  }
4219 
4220  /*
4221  * Each lock for an overlapping transaction represents a conflict: a
4222  * rw-dependency in to this transaction.
4223  */
4224  predlock = (PREDICATELOCK *)
4225  SHMQueueNext(&(target->predicateLocks),
4226  &(target->predicateLocks),
4227  offsetof(PREDICATELOCK, targetLink));
4228  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4229  while (predlock)
4230  {
4231  SHM_QUEUE *predlocktargetlink;
4232  PREDICATELOCK *nextpredlock;
4233  SERIALIZABLEXACT *sxact;
4234 
4235  predlocktargetlink = &(predlock->targetLink);
4236  nextpredlock = (PREDICATELOCK *)
4237  SHMQueueNext(&(target->predicateLocks),
4238  predlocktargetlink,
4239  offsetof(PREDICATELOCK, targetLink));
4240 
4241  sxact = predlock->tag.myXact;
4242  if (sxact == MySerializableXact)
4243  {
4244  /*
4245  * If we're getting a write lock on a tuple, we don't need a
4246  * predicate (SIREAD) lock on the same tuple. We can safely remove
4247  * our SIREAD lock, but we'll defer doing so until after the loop
4248  * because that requires upgrading to an exclusive partition lock.
4249  *
4250  * We can't use this optimization within a subtransaction because
4251  * the subtransaction could roll back, and we would be left
4252  * without any lock at the top level.
4253  */
4254  if (!IsSubTransaction()
4255  && GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
4256  {
4257  mypredlock = predlock;
4258  mypredlocktag = predlock->tag;
4259  }
4260  }
4261  else if (!SxactIsDoomed(sxact)
4262  && (!SxactIsCommitted(sxact)
4264  sxact->finishedBefore))
4266  {
4267  LWLockRelease(SerializableXactHashLock);
4268  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4269 
4270  /*
4271  * Re-check after getting exclusive lock because the other
4272  * transaction may have flagged a conflict.
4273  */
4274  if (!SxactIsDoomed(sxact)
4275  && (!SxactIsCommitted(sxact)
4277  sxact->finishedBefore))
4279  {
4281  }
4282 
4283  LWLockRelease(SerializableXactHashLock);
4284  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4285  }
4286 
4287  predlock = nextpredlock;
4288  }
4289  LWLockRelease(SerializableXactHashLock);
4290  LWLockRelease(partitionLock);
4291 
4292  /*
4293  * If we found one of our own SIREAD locks to remove, remove it now.
4294  *
4295  * At this point our transaction already has a RowExclusiveLock on the
4296  * relation, so we are OK to drop the predicate lock on the tuple, if
4297  * found, without fearing that another write against the tuple will occur
4298  * before the MVCC information makes it to the buffer.
4299  */
4300  if (mypredlock != NULL)
4301  {
4302  uint32 predlockhashcode;
4303  PREDICATELOCK *rmpredlock;
4304 
4305  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
4306  if (IsInParallelMode())
4308  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4309  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4310 
4311  /*
4312  * Remove the predicate lock from shared memory, if it wasn't removed
4313  * while the locks were released. One way that could happen is from
4314  * autovacuum cleaning up an index.
4315  */
4316  predlockhashcode = PredicateLockHashCodeFromTargetHashCode
4317  (&mypredlocktag, targettaghash);
4318  rmpredlock = (PREDICATELOCK *)
4320  &mypredlocktag,
4321  predlockhashcode,
4322  HASH_FIND, NULL);
4323  if (rmpredlock != NULL)
4324  {
4325  Assert(rmpredlock == mypredlock);
4326 
4327  SHMQueueDelete(&(mypredlock->targetLink));
4328  SHMQueueDelete(&(mypredlock->xactLink));
4329 
4330  rmpredlock = (PREDICATELOCK *)
4332  &mypredlocktag,
4333  predlockhashcode,
4334  HASH_REMOVE, NULL);
4335  Assert(rmpredlock == mypredlock);
4336 
4337  RemoveTargetIfNoLongerUsed(target, targettaghash);
4338  }
4339 
4340  LWLockRelease(SerializableXactHashLock);
4341  LWLockRelease(partitionLock);
4342  if (IsInParallelMode())
4344  LWLockRelease(SerializablePredicateLockListLock);
4345 
4346  if (rmpredlock != NULL)
4347  {
4348  /*
4349  * Remove entry in local lock table if it exists. It's OK if it
4350  * doesn't exist; that means the lock was transferred to a new
4351  * target by a different backend.
4352  */
4354  targettag, targettaghash,
4355  HASH_REMOVE, NULL);
4356 
4357  DecrementParentLocks(targettag);
4358  }
4359  }
4360 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:921
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
TransactionId finishedBefore
Definition: lwlock.h:32
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:653
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4549
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2096
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag)
bool IsInParallelMode(void)
Definition: xact.c:996
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
static HTAB * PredicateLockHash
Definition: predicate.c:393
#define InvalidSerializableXact
unsigned int uint32
Definition: c.h:367
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2314
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:738
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
bool IsSubTransaction(void)
Definition: xact.c:4723
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
SERIALIZABLEXACT * myXact
#define SxactIsCommitted(sxact)
Definition: predicate.c:272
#define offsetof(type, field)
Definition: c.h:661

◆ ClearOldPredicateLocks()

static void ClearOldPredicateLocks ( void  )
static

Definition at line 3674 of file predicate.c.

References Assert, PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, PREDICATELOCK::commitSeqNo, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, HASH_REMOVE, hash_search_with_hash_value(), PredXactListData::HavePartialClearedThrough, InvalidSerCommitSeqNo, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, offsetof, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, ReleaseOneSerializableXact(), RemoveTargetIfNoLongerUsed(), SHMQueueDelete(), SHMQueueNext(), PredXactListData::SxactGlobalXmin, SxactIsReadOnly, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdIsValid, TransactionIdPrecedesOrEquals(), and PREDICATELOCK::xactLink.

Referenced by ReleasePredicateLocks().

3675 {
3676  SERIALIZABLEXACT *finishedSxact;
3677  PREDICATELOCK *predlock;
3678 
3679  /*
3680  * Loop through finished transactions. They are in commit order, so we can
3681  * stop as soon as we find one that's still interesting.
3682  */
3683  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3684  finishedSxact = (SERIALIZABLEXACT *)
3687  offsetof(SERIALIZABLEXACT, finishedLink));
3688  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3689  while (finishedSxact)
3690  {
3691  SERIALIZABLEXACT *nextSxact;
3692 
3693  nextSxact = (SERIALIZABLEXACT *)
3695  &(finishedSxact->finishedLink),
3696  offsetof(SERIALIZABLEXACT, finishedLink));
3700  {
3701  /*
3702  * This transaction committed before any in-progress transaction
3703  * took its snapshot. It's no longer interesting.
3704  */
3705  LWLockRelease(SerializableXactHashLock);
3706  SHMQueueDelete(&(finishedSxact->finishedLink));
3707  ReleaseOneSerializableXact(finishedSxact, false, false);
3708  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3709  }
3710  else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3711  && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3712  {
3713  /*
3714  * Any active transactions that took their snapshot before this
3715  * transaction committed are read-only, so we can clear part of
3716  * its state.
3717  */
3718  LWLockRelease(SerializableXactHashLock);
3719 
3720  if (SxactIsReadOnly(finishedSxact))
3721  {
3722  /* A read-only transaction can be removed entirely */
3723  SHMQueueDelete(&(finishedSxact->finishedLink));
3724  ReleaseOneSerializableXact(finishedSxact, false, false);
3725  }
3726  else
3727  {
3728  /*
3729  * A read-write transaction can only be partially cleared. We
3730  * need to keep the SERIALIZABLEXACT but can release the
3731  * SIREAD locks and conflicts in.
3732  */
3733  ReleaseOneSerializableXact(finishedSxact, true, false);
3734  }
3735 
3737  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3738  }
3739  else
3740  {
3741  /* Still interesting. */
3742  break;
3743  }
3744  finishedSxact = nextSxact;
3745  }
3746  LWLockRelease(SerializableXactHashLock);
3747 
3748  /*
3749  * Loop through predicate locks on dummy transaction for summarized data.
3750  */
3751  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
3752  predlock = (PREDICATELOCK *)
3755  offsetof(PREDICATELOCK, xactLink));
3756  while (predlock)
3757  {
3758  PREDICATELOCK *nextpredlock;
3759  bool canDoPartialCleanup;
3760 
3761  nextpredlock = (PREDICATELOCK *)
3763  &predlock->xactLink,
3764  offsetof(PREDICATELOCK, xactLink));
3765 
3766  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3767  Assert(predlock->commitSeqNo != 0);
3769  canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
3770  LWLockRelease(SerializableXactHashLock);
3771 
3772  /*
3773  * If this lock originally belonged to an old enough transaction, we
3774  * can release it.
3775  */
3776  if (canDoPartialCleanup)
3777  {
3778  PREDICATELOCKTAG tag;
3779  PREDICATELOCKTARGET *target;
3780  PREDICATELOCKTARGETTAG targettag;
3781  uint32 targettaghash;
3782  LWLock *partitionLock;
3783 
3784  tag = predlock->tag;
3785  target = tag.myTarget;
3786  targettag = target->tag;
3787  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3788  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3789 
3790  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3791 
3792  SHMQueueDelete(&(predlock->targetLink));
3793  SHMQueueDelete(&(predlock->xactLink));
3794 
3797  targettaghash),
3798  HASH_REMOVE, NULL);
3799  RemoveTargetIfNoLongerUsed(target, targettaghash);
3800 
3801  LWLockRelease(partitionLock);
3802  }
3803 
3804  predlock = nextpredlock;
3805  }
3806 
3807  LWLockRelease(SerializablePredicateLockListLock);
3808  LWLockRelease(SerializableFinishedListLock);
3809 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:921
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
TransactionId finishedBefore
Definition: lwlock.h:32
static PredXactList PredXact
Definition: predicate.c:379
TransactionId SxactGlobalXmin
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2096
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
static HTAB * PredicateLockHash
Definition: predicate.c:393
unsigned int uint32
Definition: c.h:367
#define InvalidSerCommitSeqNo
SerCommitSeqNo commitSeqNo
SerCommitSeqNo HavePartialClearedThrough
PREDICATELOCKTAG tag
SerCommitSeqNo CanPartialClearThrough
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
SerCommitSeqNo commitSeqNo
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize)
Definition: predicate.c:3831
#define Assert(condition)
Definition: c.h:738
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:357
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static SHM_QUEUE * FinishedSerializableTransactions
Definition: predicate.c:394
#define offsetof(type, field)
Definition: c.h:661
PREDICATELOCKTARGET * myTarget

◆ CoarserLockCovers()

static bool CoarserLockCovers ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2024 of file predicate.c.

References GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

2025 {
2026  PREDICATELOCKTARGETTAG targettag,
2027  parenttag;
2028 
2029  targettag = *newtargettag;
2030 
2031  /* check parents iteratively until no more */
2032  while (GetParentPredicateLockTag(&targettag, &parenttag))
2033  {
2034  targettag = parenttag;
2035  if (PredicateLockExists(&targettag))
2036  return true;
2037  }
2038 
2039  /* no more parents to check; lock is not covered */
2040  return false;
2041 }
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:1958
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:1985

◆ CreateLocalPredicateLockHash()

static void CreateLocalPredicateLockHash ( void  )
static

Definition at line 1852 of file predicate.c.

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

Referenced by AttachSerializableXact(), and GetSerializableTransactionSnapshotInt().

1853 {
1854  HASHCTL hash_ctl;
1855 
1856  /* Initialize the backend-local hash table of parent locks */
1857  Assert(LocalPredicateLockHash == NULL);
1858  MemSet(&hash_ctl, 0, sizeof(hash_ctl));
1859  hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1860  hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1861  LocalPredicateLockHash = hash_create("Local predicate lock",
1863  &hash_ctl,
1864  HASH_ELEM | HASH_BLOBS);
1865 }
#define HASH_ELEM
Definition: hsearch.h:87
Size entrysize
Definition: hsearch.h:73
#define MemSet(start, val, len)
Definition: c.h:971
int max_predicate_locks_per_xact
Definition: predicate.c:366
struct LOCALPREDICATELOCK LOCALPREDICATELOCK
#define HASH_BLOBS
Definition: hsearch.h:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:318
Size keysize
Definition: hsearch.h:72
#define Assert(condition)
Definition: c.h:738
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409

◆ CreatePredicateLock()

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

Definition at line 2376 of file predicate.c.

References PREDICATELOCK::commitSeqNo, 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, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLockListLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, SHMQueueInit(), SHMQueueInsertBefore(), PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by predicatelock_twophase_recover(), and PredicateLockAcquire().

2379 {
2380  PREDICATELOCKTARGET *target;
2381  PREDICATELOCKTAG locktag;
2382  PREDICATELOCK *lock;
2383  LWLock *partitionLock;
2384  bool found;
2385 
2386  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2387 
2388  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
2389  if (IsInParallelMode())
2391  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2392 
2393  /* Make sure that the target is represented. */
2394  target = (PREDICATELOCKTARGET *)
2396  targettag, targettaghash,
2397  HASH_ENTER_NULL, &found);
2398  if (!target)
2399  ereport(ERROR,
2400  (errcode(ERRCODE_OUT_OF_MEMORY),
2401  errmsg("out of shared memory"),
2402  errhint("You might need to increase max_pred_locks_per_transaction.")));
2403  if (!found)
2404  SHMQueueInit(&(target->predicateLocks));
2405 
2406  /* We've got the sxact and target, make sure they're joined. */
2407  locktag.myTarget = target;
2408  locktag.myXact = sxact;
2409  lock = (PREDICATELOCK *)
2411  PredicateLockHashCodeFromTargetHashCode(&locktag, targettaghash),
2412  HASH_ENTER_NULL, &found);
2413  if (!lock)
2414  ereport(ERROR,
2415  (errcode(ERRCODE_OUT_OF_MEMORY),
2416  errmsg("out of shared memory"),
2417  errhint("You might need to increase max_pred_locks_per_transaction.")));
2418 
2419  if (!found)
2420  {
2421  SHMQueueInsertBefore(&(target->predicateLocks), &(lock->targetLink));
2423  &(lock->xactLink));
2425  }
2426 
2427  LWLockRelease(partitionLock);
2428  if (IsInParallelMode())
2430  LWLockRelease(SerializablePredicateLockListLock);
2431 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:921
Definition: lwlock.h:32
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
int errhint(const char *fmt,...)
Definition: elog.c:1071
int errcode(int sqlerrcode)
Definition: elog.c:610
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
bool IsInParallelMode(void)
Definition: xact.c:996
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
#define ERROR
Definition: elog.h:43
static HTAB * PredicateLockHash
Definition: predicate.c:393
#define InvalidSerCommitSeqNo
#define ereport(elevel,...)
Definition: elog.h:144
SerCommitSeqNo commitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
int errmsg(const char *fmt,...)
Definition: elog.c:824
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
SERIALIZABLEXACT * myXact
PREDICATELOCKTARGET * myTarget

◆ CreatePredXact()

static SERIALIZABLEXACT * CreatePredXact ( void  )
static

Definition at line 580 of file predicate.c.

References PredXactListData::activeList, PredXactListData::availableList, PredXactListElementData::link, offsetof, SHMQueueDelete(), SHMQueueInsertBefore(), SHMQueueNext(), and PredXactListElementData::sxact.

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

581 {
582  PredXactListElement ptle;
583 
584  ptle = (PredXactListElement)
588  if (!ptle)
589  return NULL;
590 
591  SHMQueueDelete(&ptle->link);
593  return &ptle->sxact;
594 }
static PredXactList PredXact
Definition: predicate.c:379
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
struct PredXactListElementData * PredXactListElement
#define offsetof(type, field)
Definition: c.h:661

◆ DecrementParentLocks()

static void DecrementParentLocks ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2314 of file predicate.c.

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

Referenced by CheckTargetForConflictsIn(), and DeleteChildTargetLocks().

2315 {
2316  PREDICATELOCKTARGETTAG parenttag,
2317  nexttag;
2318 
2319  parenttag = *targettag;
2320 
2321  while (GetParentPredicateLockTag(&parenttag, &nexttag))
2322  {
2323  uint32 targettaghash;
2324  LOCALPREDICATELOCK *parentlock,
2325  *rmlock PG_USED_FOR_ASSERTS_ONLY;
2326 
2327  parenttag = nexttag;
2328  targettaghash = PredicateLockTargetTagHashCode(&parenttag);
2329  parentlock = (LOCALPREDICATELOCK *)
2331  &parenttag, targettaghash,
2332  HASH_FIND, NULL);
2333 
2334  /*
2335  * There's a small chance the parent lock doesn't exist in the lock
2336  * table. This can happen if we prematurely removed it because an
2337  * index split caused the child refcount to be off.
2338  */
2339  if (parentlock == NULL)
2340  continue;
2341 
2342  parentlock->childLocks--;
2343 
2344  /*
2345  * Under similar circumstances the parent lock's refcount might be
2346  * zero. This only happens if we're holding that lock (otherwise we
2347  * would have removed the entry).
2348  */
2349  if (parentlock->childLocks < 0)
2350  {
2351  Assert(parentlock->held);
2352  parentlock->childLocks = 0;
2353  }
2354 
2355  if ((parentlock->childLocks == 0) && (!parentlock->held))
2356  {
2357  rmlock = (LOCALPREDICATELOCK *)
2359  &parenttag, targettaghash,
2360  HASH_REMOVE, NULL);
2361  Assert(rmlock == parentlock);
2362  }
2363  }
2364 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:921
unsigned int uint32
Definition: c.h:367
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:1985
#define Assert(condition)
Definition: c.h:738
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:121

◆ DeleteChildTargetLocks()

static void DeleteChildTargetLocks ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2127 of file predicate.c.

References Assert, DecrementParentLocks(), HASH_REMOVE, hash_search_with_hash_value(), IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, offsetof, PG_USED_FOR_ASSERTS_ONLY, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLockListLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, RemoveTargetIfNoLongerUsed(), SHMQueueDelete(), SHMQueueNext(), PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TargetTagIsCoveredBy, and PREDICATELOCK::xactLink.

Referenced by PredicateLockAcquire().

2128 {
2129  SERIALIZABLEXACT *sxact;
2130  PREDICATELOCK *predlock;
2131 
2132  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
2133  sxact = MySerializableXact;
2134  if (IsInParallelMode())
2136  predlock = (PREDICATELOCK *)
2137  SHMQueueNext(&(sxact->predicateLocks),
2138  &(sxact->predicateLocks),
2139  offsetof(PREDICATELOCK, xactLink));
2140  while (predlock)
2141  {
2142  SHM_QUEUE *predlocksxactlink;
2143  PREDICATELOCK *nextpredlock;
2144  PREDICATELOCKTAG oldlocktag;
2145  PREDICATELOCKTARGET *oldtarget;
2146  PREDICATELOCKTARGETTAG oldtargettag;
2147 
2148  predlocksxactlink = &(predlock->xactLink);
2149  nextpredlock = (PREDICATELOCK *)
2150  SHMQueueNext(&(sxact->predicateLocks),
2151  predlocksxactlink,
2152  offsetof(PREDICATELOCK, xactLink));
2153 
2154  oldlocktag = predlock->tag;
2155  Assert(oldlocktag.myXact == sxact);
2156  oldtarget = oldlocktag.myTarget;
2157  oldtargettag = oldtarget->tag;
2158 
2159  if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
2160  {
2161  uint32 oldtargettaghash;
2162  LWLock *partitionLock;
2164 
2165  oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2166  partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2167 
2168  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2169 
2170  SHMQueueDelete(predlocksxactlink);
2171  SHMQueueDelete(&(predlock->targetLink));
2172  rmpredlock = hash_search_with_hash_value
2174  &oldlocktag,
2176  oldtargettaghash),
2177  HASH_REMOVE, NULL);
2178  Assert(rmpredlock == predlock);
2179 
2180  RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2181 
2182  LWLockRelease(partitionLock);
2183 
2184  DecrementParentLocks(&oldtargettag);
2185  }
2186 
2187  predlock = nextpredlock;
2188  }
2189  if (IsInParallelMode())
2191  LWLockRelease(SerializablePredicateLockListLock);
2192 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:921
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
Definition: lwlock.h:32
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2096
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
bool IsInParallelMode(void)
Definition: xact.c:996
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
static HTAB * PredicateLockHash
Definition: predicate.c:393
unsigned int uint32
Definition: c.h:367
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2314
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:738
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
#define TargetTagIsCoveredBy(covered_target, covering_target)
Definition: predicate.c:228
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
SERIALIZABLEXACT * myXact
#define offsetof(type, field)
Definition: c.h:661
PREDICATELOCKTARGET * myTarget
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:121

◆ DeleteLockTarget()

static void DeleteLockTarget ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

Definition at line 2593 of file predicate.c.

References Assert, HASH_REMOVE, hash_search_with_hash_value(), LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMe(), LWLockHeldByMeInMode(), LWLockRelease(), offsetof, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PREDICATELOCKTARGET::predicateLocks, RemoveTargetIfNoLongerUsed(), SHMQueueDelete(), SHMQueueNext(), PREDICATELOCK::tag, PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by TransferPredicateLocksToNewTarget().

2594 {
2595  PREDICATELOCK *predlock;
2596  SHM_QUEUE *predlocktargetlink;
2597  PREDICATELOCK *nextpredlock;
2598  bool found;
2599 
2600  Assert(LWLockHeldByMeInMode(SerializablePredicateLockListLock,
2601  LW_EXCLUSIVE));
2603 
2604  predlock = (PREDICATELOCK *)
2605  SHMQueueNext(&(target->predicateLocks),
2606  &(target->predicateLocks),
2607  offsetof(PREDICATELOCK, targetLink));
2608  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2609  while (predlock)
2610  {
2611  predlocktargetlink = &(predlock->targetLink);
2612  nextpredlock = (PREDICATELOCK *)
2613  SHMQueueNext(&(target->predicateLocks),
2614  predlocktargetlink,
2615  offsetof(PREDICATELOCK, targetLink));
2616 
2617  SHMQueueDelete(&(predlock->xactLink));
2618  SHMQueueDelete(&(predlock->targetLink));
2619 
2622  &predlock->tag,
2624  targettaghash),
2625  HASH_REMOVE, &found);
2626  Assert(found);
2627 
2628  predlock = nextpredlock;
2629  }
2630  LWLockRelease(SerializableXactHashLock);
2631 
2632  /* Remove the target itself, if possible. */
2633  RemoveTargetIfNoLongerUsed(target, targettaghash);
2634 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:921
bool LWLockHeldByMeInMode(LWLock *l, LWLockMode mode)
Definition: lwlock.c:1861
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1843
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2096
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
static HTAB * PredicateLockHash
Definition: predicate.c:393
PREDICATELOCKTAG tag
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:738
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
#define offsetof(type, field)
Definition: c.h:661

◆ DropAllPredicateLocksFromTable()

static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
)
static

Definition at line 2881 of file predicate.c.

References Assert, PREDICATELOCK::commitSeqNo, RelFileNode::dbNode, 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, offsetof, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLockByIndex, PredicateLockingNeededForRelation(), SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetTagHashCode, PREDLOCKTAG_RELATION, RelationData::rd_id, RelationData::rd_index, RelationData::rd_node, RemoveScratchTarget(), RestoreScratchTarget(), SET_PREDICATELOCKTARGETTAG_RELATION, SHMQueueDelete(), SHMQueueInit(), SHMQueueInsertBefore(), SHMQueueNext(), PredXactListData::SxactGlobalXmin, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdIsValid, and PREDICATELOCK::xactLink.

Referenced by TransferPredicateLocksToHeapRelation().

2882 {
2883  HASH_SEQ_STATUS seqstat;
2884  PREDICATELOCKTARGET *oldtarget;
2885  PREDICATELOCKTARGET *heaptarget;
2886  Oid dbId;
2887  Oid relId;
2888  Oid heapId;
2889  int i;
2890  bool isIndex;
2891  bool found;
2892  uint32 heaptargettaghash;
2893 
2894  /*
2895  * Bail out quickly if there are no serializable transactions running.
2896  * It's safe to check this without taking locks because the caller is
2897  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
2898  * would matter here can be acquired while that is held.
2899  */
2901  return;
2902 
2903  if (!PredicateLockingNeededForRelation(relation))
2904  return;
2905 
2906  dbId = relation->rd_node.dbNode;
2907  relId = relation->rd_id;
2908  if (relation->rd_index == NULL)
2909  {
2910  isIndex = false;
2911  heapId = relId;
2912  }
2913  else
2914  {
2915  isIndex = true;
2916  heapId = relation->rd_index->indrelid;
2917  }
2918  Assert(heapId != InvalidOid);
2919  Assert(transfer || !isIndex); /* index OID only makes sense with
2920  * transfer */
2921 
2922  /* Retrieve first time needed, then keep. */
2923  heaptargettaghash = 0;
2924  heaptarget = NULL;
2925 
2926  /* Acquire locks on all lock partitions */
2927  LWLockAcquire(SerializablePredicateLockListLock, LW_EXCLUSIVE);
2928  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
2930  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2931 
2932  /*
2933  * Remove the dummy entry to give us scratch space, so we know we'll be
2934  * able to create the new lock target.
2935  */
2936  if (transfer)
2937  RemoveScratchTarget(true);
2938 
2939  /* Scan through target map */
2941 
2942  while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
2943  {
2944  PREDICATELOCK *oldpredlock;
2945 
2946  /*
2947  * Check whether this is a target which needs attention.
2948  */
2949  if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) != relId)
2950  continue; /* wrong relation id */
2951  if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
2952  continue; /* wrong database id */
2953  if (transfer && !isIndex
2955  continue; /* already the right lock */
2956 
2957  /*
2958  * If we made it here, we have work to do. We make sure the heap
2959  * relation lock exists, then we walk the list of predicate locks for
2960  * the old target we found, moving all locks to the heap relation lock
2961  * -- unless they already hold that.
2962  */
2963 
2964  /*
2965  * First make sure we have the heap relation target. We only need to
2966  * do this once.
2967  */
2968  if (transfer && heaptarget == NULL)
2969  {
2970  PREDICATELOCKTARGETTAG heaptargettag;
2971 
2972  SET_PREDICATELOCKTARGETTAG_RELATION(heaptargettag, dbId, heapId);
2973  heaptargettaghash = PredicateLockTargetTagHashCode(&heaptargettag);
2975  &heaptargettag,
2976  heaptargettaghash,
2977  HASH_ENTER, &found);
2978  if (!found)
2979  SHMQueueInit(&heaptarget->predicateLocks);
2980  }
2981 
2982  /*
2983  * Loop through all the locks on the old target, replacing them with
2984  * locks on the new target.
2985  */
2986  oldpredlock = (PREDICATELOCK *)
2987  SHMQueueNext(&(oldtarget->predicateLocks),
2988  &(oldtarget->predicateLocks),
2989  offsetof(PREDICATELOCK, targetLink));
2990  while (oldpredlock)
2991  {
2992  PREDICATELOCK *nextpredlock;
2993  PREDICATELOCK *newpredlock;
2994  SerCommitSeqNo oldCommitSeqNo;
2995  SERIALIZABLEXACT *oldXact;
2996 
2997  nextpredlock = (PREDICATELOCK *)
2998  SHMQueueNext(&(oldtarget->predicateLocks),
2999  &(oldpredlock->targetLink),
3000  offsetof(PREDICATELOCK, targetLink));
3001 
3002  /*
3003  * Remove the old lock first. This avoids the chance of running
3004  * out of lock structure entries for the hash table.
3005  */
3006  oldCommitSeqNo = oldpredlock->commitSeqNo;
3007  oldXact = oldpredlock->tag.myXact;
3008 
3009  SHMQueueDelete(&(oldpredlock->xactLink));
3010 
3011  /*
3012  * No need for retail delete from oldtarget list, we're removing
3013  * the whole target anyway.
3014  */
3016  &oldpredlock->tag,
3017  HASH_REMOVE, &found);
3018  Assert(found);
3019 
3020  if (transfer)
3021  {
3022  PREDICATELOCKTAG newpredlocktag;
3023 
3024  newpredlocktag.myTarget = heaptarget;
3025  newpredlocktag.myXact = oldXact;
3026  newpredlock = (PREDICATELOCK *)
3028  &newpredlocktag,
3030  heaptargettaghash),
3031  HASH_ENTER,
3032  &found);
3033  if (!found)
3034  {
3035  SHMQueueInsertBefore(&(heaptarget->predicateLocks),
3036  &(newpredlock->targetLink));
3037  SHMQueueInsertBefore(&(newpredlocktag.myXact->predicateLocks),
3038  &(newpredlock->xactLink));
3039  newpredlock->commitSeqNo = oldCommitSeqNo;
3040  }
3041  else
3042  {
3043  if (newpredlock->commitSeqNo < oldCommitSeqNo)
3044  newpredlock->commitSeqNo = oldCommitSeqNo;
3045  }
3046 
3047  Assert(newpredlock->commitSeqNo != 0);
3048  Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
3049  || (newpredlock->tag.myXact == OldCommittedSxact));
3050  }
3051 
3052  oldpredlock = nextpredlock;
3053  }
3054 
3056  &found);
3057  Assert(found);
3058  }
3059 
3060  /* Put the scratch entry back */
3061  if (transfer)
3062  RestoreScratchTarget(true);
3063 
3064  /* Release locks in reverse order */
3065  LWLockRelease(SerializableXactHashLock);
3066  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3068  LWLockRelease(SerializablePredicateLockListLock);
3069 }
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:921
static bool PredicateLockingNeededForRelation(Relation relation)
Definition: predicate.c:495
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
static PredXactList PredXact
Definition: predicate.c:379
TransactionId SxactGlobalXmin
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:908
unsigned int Oid
Definition: postgres_ext.h:31
#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag, dboid, reloid)
static void RemoveScratchTarget(bool lockheld)
Definition: predicate.c:2053
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
Form_pg_index rd_index
Definition: rel.h:174
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
static HTAB * PredicateLockHash
Definition: predicate.c:393
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
unsigned int uint32
Definition: c.h:367
Oid rd_id
Definition: rel.h:111
#define InvalidSerCommitSeqNo
static void RestoreScratchTarget(bool lockheld)
Definition: predicate.c:2074
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define InvalidOid
Definition: postgres_ext.h:36
PREDICATELOCKTARGETTAG tag
RelFileNode rd_node
Definition: rel.h:55
SerCommitSeqNo commitSeqNo
uint64 SerCommitSeqNo
#define Assert(condition)
Definition: c.h:738
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1391
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1381
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:357
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:256
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
int i
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
SERIALIZABLEXACT * myXact
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define offsetof(type, field)
Definition: c.h:661
PREDICATELOCKTARGET * myTarget
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:121

◆ FirstPredXact()

static SERIALIZABLEXACT * FirstPredXact ( void  )
static

Definition at line 612 of file predicate.c.

References PredXactListData::activeList, offsetof, SHMQueueNext(), and PredXactListElementData::sxact.

Referenced by GetSafeSnapshotBlockingPids(), GetSerializableTransactionSnapshotInt(), and SetNewSxactGlobalXmin().

613 {
614  PredXactListElement ptle;
615 
616  ptle = (PredXactListElement)
620  if (!ptle)
621  return NULL;
622 
623  return &ptle->sxact;
624 }
static PredXactList PredXact
Definition: predicate.c:379
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
struct PredXactListElementData * PredXactListElement
#define offsetof(type, field)
Definition: c.h:661

◆ FlagRWConflict()

static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4549 of file predicate.c.

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

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

4550 {
4551  Assert(reader != writer);
4552 
4553  /* First, see if this conflict causes failure. */
4555 
4556  /* Actually do the conflict flagging. */
4557  if (reader == OldCommittedSxact)
4559  else if (writer == OldCommittedSxact)
4561  else
4562  SetRWConflict(reader, writer);
4563 }
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:686
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4584
#define Assert(condition)
Definition: c.h:738
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:357
#define SXACT_FLAG_SUMMARY_CONFLICT_IN

◆ FlagSxactUnsafe()

static void FlagSxactUnsafe ( SERIALIZABLEXACT sxact)
static

Definition at line 750 of file predicate.c.

References Assert, SERIALIZABLEXACT::flags, RWConflictData::inLink, offsetof, SERIALIZABLEXACT::possibleUnsafeConflicts, ReleaseRWConflict(), SHMQueueNext(), SXACT_FLAG_RO_UNSAFE, RWConflictData::sxactIn, SxactIsReadOnly, SxactIsROSafe, and RWConflictData::sxactOut.

Referenced by ReleasePredicateLocks().

751 {
752  RWConflict conflict,
753  nextConflict;
754 
755  Assert(SxactIsReadOnly(sxact));
756  Assert(!SxactIsROSafe(sxact));
757 
758  sxact->flags |= SXACT_FLAG_RO_UNSAFE;
759 
760  /*
761  * We know this isn't a safe snapshot, so we can stop looking for other
762  * potential conflicts.
763  */
764  conflict = (RWConflict)
766  &sxact->possibleUnsafeConflicts,
767  offsetof(RWConflictData, inLink));
768  while (conflict)
769  {
770  nextConflict = (RWConflict)
772  &conflict->inLink,
773  offsetof(RWConflictData, inLink));
774 
775  Assert(!SxactIsReadOnly(conflict->sxactOut));
776  Assert(sxact == conflict->sxactIn);
777 
778  ReleaseRWConflict(conflict);
779 
780  conflict = nextConflict;
781  }
782 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
struct RWConflictData * RWConflict
static void ReleaseRWConflict(RWConflict conflict)
Definition: predicate.c:742
SERIALIZABLEXACT * sxactIn
SHM_QUEUE possibleUnsafeConflicts
#define SxactIsROSafe(sxact)
Definition: predicate.c:286
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:738
#define SXACT_FLAG_RO_UNSAFE
#define offsetof(type, field)
Definition: c.h:661
SERIALIZABLEXACT * sxactOut

◆ GetParentPredicateLockTag()

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

Definition at line 1985 of file predicate.c.

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().

1987 {
1988  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
1989  {
1990  case PREDLOCKTAG_RELATION:
1991  /* relation locks have no parent lock */
1992  return false;
1993 
1994  case PREDLOCKTAG_PAGE:
1995  /* parent lock is relation lock */
1999 
2000  return true;
2001 
2002  case PREDLOCKTAG_TUPLE:
2003  /* parent lock is page lock */
2008  return true;
2009  }
2010 
2011  /* not reachable */
2012  Assert(false);
2013  return false;
2014 }
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
#define GET_PREDICATELOCKTARGETTAG_PAGE(locktag)
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag, dboid, reloid)
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
#define Assert(condition)
Definition: c.h:738

◆ GetPredicateLockStatusData()

PredicateLockData* GetPredicateLockStatusData ( void  )

Definition at line 1373 of file predicate.c.

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

Referenced by pg_lock_status().

1374 {
1375  PredicateLockData *data;
1376  int i;
1377  int els,
1378  el;
1379  HASH_SEQ_STATUS seqstat;
1380  PREDICATELOCK *predlock;
1381 
1382  data = (PredicateLockData *) palloc(sizeof(PredicateLockData));
1383 
1384  /*
1385  * To ensure consistency, take simultaneous locks on all partition locks
1386  * in ascending order, then SerializableXactHashLock.
1387  */
1388  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
1390  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1391 
1392  /* Get number of locks and allocate appropriately-sized arrays. */
1394  data->nelements = els;
1395  data->locktags = (PREDICATELOCKTARGETTAG *)
1396  palloc(sizeof(PREDICATELOCKTARGETTAG) * els);
1397  data->xacts = (SERIALIZABLEXACT *)
1398  palloc(sizeof(SERIALIZABLEXACT) * els);
1399 
1400 
1401  /* Scan through PredicateLockHash and copy contents */
1402  hash_seq_init(&seqstat, PredicateLockHash);
1403 
1404  el = 0;
1405 
1406  while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
1407  {
1408  data->locktags[el] = predlock->tag.myTarget->tag;
1409  data->xacts[el] = *predlock->tag.myXact;
1410  el++;
1411  }
1412 
1413  Assert(el == els);
1414 
1415  /* Release locks in reverse order */
1416  LWLockRelease(SerializableXactHashLock);
1417  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1419 
1420  return data;
1421 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1337
SERIALIZABLEXACT * xacts
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
static HTAB * PredicateLockHash
Definition: predicate.c:393
PREDICATELOCKTARGETTAG * locktags
PREDICATELOCKTAG tag
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:738
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1391
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1381
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:256
void * palloc(Size size)
Definition: mcxt.c:949
int i
SERIALIZABLEXACT * myXact
PREDICATELOCKTARGET * myTarget
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:121

◆ GetSafeSnapshot()

static Snapshot GetSafeSnapshot ( Snapshot  snapshot)
static

Definition at line 1488 of file predicate.c.

References Assert, DEBUG2, ereport, errcode(), errmsg(), SERIALIZABLEXACT::flags, GetSerializableTransactionSnapshotInt(), InvalidPid, InvalidSerializableXact, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SERIALIZABLEXACT::possibleUnsafeConflicts, ProcWaitForSignal(), ReleasePredicateLocks(), SHMQueueEmpty(), SXACT_FLAG_DEFERRABLE_WAITING, SxactIsROSafe, SxactIsROUnsafe, WAIT_EVENT_SAFE_SNAPSHOT, XactDeferrable, and XactReadOnly.

Referenced by GetSerializableTransactionSnapshot().

1489 {
1490  Snapshot snapshot;
1491 
1493 
1494  while (true)
1495  {
1496  /*
1497  * GetSerializableTransactionSnapshotInt is going to call
1498  * GetSnapshotData, so we need to provide it the static snapshot area
1499  * our caller passed to us. The pointer returned is actually the same
1500  * one passed to it, but we avoid assuming that here.
1501  */
1502  snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
1503  NULL, InvalidPid);
1504 
1506  return snapshot; /* no concurrent r/w xacts; it's safe */
1507 
1508  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1509 
1510  /*
1511  * Wait for concurrent transactions to finish. Stop early if one of
1512  * them marked us as conflicted.
1513  */
1517  {
1518  LWLockRelease(SerializableXactHashLock);
1520  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1521  }
1523 
1525  {
1526  LWLockRelease(SerializableXactHashLock);
1527  break; /* success */
1528  }
1529 
1530  LWLockRelease(SerializableXactHashLock);
1531 
1532  /* else, need to retry... */
1533  ereport(DEBUG2,
1534  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1535  errmsg("deferrable snapshot was unsafe; trying a new one")));
1536  ReleasePredicateLocks(false, false);
1537  }
1538 
1539  /*
1540  * Now we have a safe snapshot, so we don't need to do any further checks.
1541  */
1543  ReleasePredicateLocks(false, true);
1544 
1545  return snapshot;
1546 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
bool XactDeferrable
Definition: xact.c:80
int errcode(int sqlerrcode)
Definition: elog.c:610
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3263
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1692
SHM_QUEUE possibleUnsafeConflicts
#define InvalidSerializableXact
#define SXACT_FLAG_DEFERRABLE_WAITING
#define DEBUG2
Definition: elog.h:24
#define SxactIsROSafe(sxact)
Definition: predicate.c:286
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1800
bool SHMQueueEmpty(const SHM_QUEUE *queue)
Definition: shmqueue.c:180
#define ereport(elevel,...)
Definition: elog.h:144
bool XactReadOnly
Definition: xact.c:77
#define Assert(condition)
Definition: c.h:738
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define SxactIsROUnsafe(sxact)
Definition: predicate.c:287
#define InvalidPid
Definition: miscadmin.h:32

◆ GetSafeSnapshotBlockingPids()

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

Definition at line 1558 of file predicate.c.

References FirstPredXact(), RWConflictData::inLink, LW_SHARED, LWLockAcquire(), LWLockRelease(), NextPredXact(), offsetof, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SHMQueueNext(), SxactIsDeferrableWaiting, and RWConflictData::sxactOut.

Referenced by pg_isolation_test_session_is_blocked(), and pg_safe_snapshot_blocking_pids().

1559 {
1560  int num_written = 0;
1561  SERIALIZABLEXACT *sxact;
1562 
1563  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1564 
1565  /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
1566  for (sxact = FirstPredXact(); sxact != NULL; sxact = NextPredXact(sxact))
1567  {
1568  if (sxact->pid == blocked_pid)
1569  break;
1570  }
1571 
1572  /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
1573  if (sxact != NULL && SxactIsDeferrableWaiting(sxact))
1574  {
1575  RWConflict possibleUnsafeConflict;
1576 
1577  /* Traverse the list of possible unsafe conflicts collecting PIDs. */
1578  possibleUnsafeConflict = (RWConflict)
1580  &sxact->possibleUnsafeConflicts,
1581  offsetof(RWConflictData, inLink));
1582 
1583  while (possibleUnsafeConflict != NULL && num_written < output_size)
1584  {
1585  output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
1586  possibleUnsafeConflict = (RWConflict)
1588  &possibleUnsafeConflict->inLink,
1589  offsetof(RWConflictData, inLink));
1590  }
1591  }
1592 
1593  LWLockRelease(SerializableXactHashLock);
1594 
1595  return num_written;
1596 }
static void output(uint64 loop_count)
struct RWConflictData * RWConflict
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
SHM_QUEUE possibleUnsafeConflicts
static SERIALIZABLEXACT * NextPredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:627
static SERIALIZABLEXACT * FirstPredXact(void)
Definition: predicate.c:612
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define SxactIsDeferrableWaiting(sxact)
Definition: predicate.c:285
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
#define offsetof(type, field)
Definition: c.h:661
SERIALIZABLEXACT * sxactOut

◆ GetSerializableTransactionSnapshot()

Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot)

Definition at line 1610 of file predicate.c.

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

Referenced by GetTransactionSnapshot().

1611 {
1613 
1614  /*
1615  * Can't use serializable mode while recovery is still active, as it is,
1616  * for example, on a hot standby. We could get here despite the check in
1617  * check_XactIsoLevel() if default_transaction_isolation is set to
1618  * serializable, so phrase the hint accordingly.
1619  */
1620  if (RecoveryInProgress())
1621  ereport(ERROR,
1622  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1623  errmsg("cannot use serializable mode in a hot standby"),
1624  errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1625  errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1626 
1627  /*
1628  * A special optimization is available for SERIALIZABLE READ ONLY
1629  * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1630  * thereby avoid all SSI overhead once it's running.
1631  */
1633  return GetSafeSnapshot(snapshot);
1634 
1635  return GetSerializableTransactionSnapshotInt(snapshot,
1636  NULL, InvalidPid);
1637 }
bool XactDeferrable
Definition: xact.c:80
int errhint(const char *fmt,...)
Definition: elog.c:1071
static Snapshot GetSafeSnapshot(Snapshot snapshot)
Definition: predicate.c:1488
int errcode(int sqlerrcode)
Definition: elog.c:610
bool RecoveryInProgress(void)
Definition: xlog.c:8043
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1692
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:957
#define ereport(elevel,...)
Definition: elog.h:144
bool XactReadOnly
Definition: xact.c:77
#define Assert(condition)
Definition: c.h:738
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define IsolationIsSerializable()
Definition: xact.h:52
#define InvalidPid
Definition: miscadmin.h:32

◆ GetSerializableTransactionSnapshotInt()

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

Definition at line 1692 of file predicate.c.

References Assert, SERIALIZABLEXACT::commitSeqNo, CreateLocalPredicateLockHash(), CreatePredXact(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FirstPredXact(), 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, MyProcPid, MyXactDidWrite, NextPredXact(), OldSerXidSetActiveSerXmin(), SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::predicateLocks, SERIALIZABLEXACT::prepareSeqNo, ProcArrayInstallImportedXmin(), RecoveryInProgress(), ReleasePredXact(), SERIALIZABLEXACT::SeqNo, SetPossibleUnsafeConflict(), SHMQueueElemInit(), SHMQueueInit(), 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().

1695 {
1696  PGPROC *proc;
1697  VirtualTransactionId vxid;
1698  SERIALIZABLEXACT *sxact,
1699  *othersxact;
1700 
1701  /* We only do this for serializable transactions. Once. */
1703 
1705 
1706  /*
1707  * Since all parts of a serializable transaction must use the same
1708  * snapshot, it is too late to establish one after a parallel operation
1709  * has begun.
1710  */
1711  if (IsInParallelMode())
1712  elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
1713 
1714  proc = MyProc;
1715  Assert(proc != NULL);
1716  GET_VXID_FROM_PGPROC(vxid, *proc);
1717 
1718  /*
1719  * First we get the sxact structure, which may involve looping and access
1720  * to the "finished" list to free a structure for use.
1721  *
1722  * We must hold SerializableXactHashLock when taking/checking the snapshot
1723  * to avoid race conditions, for much the same reasons that
1724  * GetSnapshotData takes the ProcArrayLock. Since we might have to
1725  * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
1726  * this means we have to create the sxact first, which is a bit annoying
1727  * (in particular, an elog(ERROR) in procarray.c would cause us to leak
1728  * the sxact). Consider refactoring to avoid this.
1729  */
1730 #ifdef TEST_OLDSERXID
1732 #endif
1733  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1734  do
1735  {
1736  sxact = CreatePredXact();
1737  /* If null, push out committed sxact to SLRU summary & retry. */
1738  if (!sxact)
1739  {
1740  LWLockRelease(SerializableXactHashLock);
1742  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1743  }
1744  } while (!sxact);
1745 
1746  /* Get the snapshot, or check that it's safe to use */
1747  if (!sourcevxid)
1748  snapshot = GetSnapshotData(snapshot);
1749  else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid))
1750  {
1751  ReleasePredXact(sxact);
1752  LWLockRelease(SerializableXactHashLock);
1753  ereport(ERROR,
1754  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1755  errmsg("could not import the requested snapshot"),
1756  errdetail("The source process with PID %d is not running anymore.",
1757  sourcepid)));
1758  }
1759 
1760  /*
1761  * If there are no serializable transactions which are not read-only, we
1762  * can "opt out" of predicate locking and conflict checking for a
1763  * read-only transaction.
1764  *
1765  * The reason this is safe is that a read-only transaction can only become
1766  * part of a dangerous structure if it overlaps a writable transaction
1767  * which in turn overlaps a writable transaction which committed before
1768  * the read-only transaction started. A new writable transaction can
1769  * overlap this one, but it can't meet the other condition of overlapping
1770  * a transaction which committed before this one started.
1771  */
1773  {
1774  ReleasePredXact(sxact);
1775  LWLockRelease(SerializableXactHashLock);
1776  return snapshot;
1777  }
1778 
1779  /* Maintain serializable global xmin info. */
1781  {
1783  PredXact->SxactGlobalXmin = snapshot->xmin;
1785  OldSerXidSetActiveSerXmin(snapshot->xmin);
1786  }
1787  else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
1788  {
1791  }
1792  else
1793  {
1795  }
1796 
1797  /* Initialize the structure. */
1798  sxact->vxid = vxid;
1802  SHMQueueInit(&(sxact->outConflicts));
1803  SHMQueueInit(&(sxact->inConflicts));
1805  sxact->topXid = GetTopTransactionIdIfAny();
1807  sxact->xmin = snapshot->xmin;
1808  sxact->pid = MyProcPid;
1809  SHMQueueInit(&(sxact->predicateLocks));
1810  SHMQueueElemInit(&(sxact->finishedLink));
1811  sxact->flags = 0;
1812  if (XactReadOnly)
1813  {
1814  sxact->flags |= SXACT_FLAG_READ_ONLY;
1815 
1816  /*
1817  * Register all concurrent r/w transactions as possible conflicts; if
1818  * all of them commit without any outgoing conflicts to earlier
1819  * transactions then this snapshot can be deemed safe (and we can run
1820  * without tracking predicate locks).
1821  */
1822  for (othersxact = FirstPredXact();
1823  othersxact != NULL;
1824  othersxact = NextPredXact(othersxact))
1825  {
1826  if (!SxactIsCommitted(othersxact)
1827  && !SxactIsDoomed(othersxact)
1828  && !SxactIsReadOnly(othersxact))
1829  {
1830  SetPossibleUnsafeConflict(sxact, othersxact);
1831  }
1832  }
1833  }
1834  else
1835  {
1839  }
1840 
1841  MySerializableXact = sxact;
1842  MyXactDidWrite = false; /* haven't written anything yet */
1843 
1844  LWLockRelease(SerializableXactHashLock);
1845 
1847 
1848  return snapshot;
1849 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
TransactionId finishedBefore
int MyProcPid
Definition: globals.c:40
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:79
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
PGPROC * MyProc
Definition: proc.c:67
static PredXactList PredXact
Definition: predicate.c:379
TransactionId SxactGlobalXmin
int errcode(int sqlerrcode)
Definition: elog.c:610
bool RecoveryInProgress(void)
Definition: xlog.c:8043
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
bool IsInParallelMode(void)
Definition: xact.c:996
SHM_QUEUE possibleUnsafeConflicts
#define ERROR
Definition: elog.h:43
int max_prepared_xacts
Definition: twophase.c:117
#define InvalidSerializableXact
static void ReleasePredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:597
int MaxBackends
Definition: globals.c:135
VirtualTransactionId vxid
static SERIALIZABLEXACT * NextPredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:627
int errdetail(const char *fmt,...)
Definition: elog.c:957
#define InvalidTransactionId
Definition: transam.h:31
TransactionId xmin
Definition: snapshot.h:157
SerCommitSeqNo lastCommitBeforeSnapshot
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:409
#define InvalidSerCommitSeqNo
static SERIALIZABLEXACT * FirstPredXact(void)
Definition: predicate.c:612
SerCommitSeqNo commitSeqNo
#define ereport(elevel,...)
Definition: elog.h:144
bool XactReadOnly
Definition: xact.c:77
#define Assert(condition)
Definition: c.h:738
static void OldSerXidSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:964
SerCommitSeqNo prepareSeqNo
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:1506
SerCommitSeqNo LastSxactCommitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
void SHMQueueElemInit(SHM_QUEUE *queue)
Definition: shmqueue.c:57
int errmsg(const char *fmt,...)
Definition: elog.c:824
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
union SERIALIZABLEXACT::@107 SeqNo
static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
Definition: predicate.c:712
#define elog(elevel,...)
Definition: elog.h:214
#define SXACT_FLAG_READ_ONLY
static void SummarizeOldestCommittedSxact(void)
Definition: predicate.c:1431
static bool MyXactDidWrite
Definition: predicate.c:417
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1852
#define TransactionIdIsValid(xid)
Definition: transam.h:41
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition: procarray.c:1797
Definition: proc.h:95
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:580
#define SxactIsCommitted(sxact)
Definition: predicate.c:272

◆ InitPredicateLocks()

void InitPredicateLocks ( void  )

Definition at line 1080 of file predicate.c.

References PredXactListData::activeList, Assert, PredXactListData::availableList, RWConflictPoolHeaderData::availableList, PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, CreatePredXact(), PredXactListData::element, RWConflictPoolHeaderData::element, HASHCTL::entrysize, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, 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, InvalidTransactionId, IsUnderPostmaster, HASHCTL::keysize, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, PredXactListElementData::link, LWLockInitialize(), LWTRANCHE_SXACT, max_prepared_xacts, MaxBackends, MemSet, mul_size(), NPREDICATELOCKTARGETENTS, HASHCTL::num_partitions, NUM_PREDICATELOCK_PARTITIONS, PredXactListData::OldCommittedSxact, OldSerXidInit(), SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, predicatelock_hash(), PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLockListLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, PredXactListDataSize, PredXactListElementDataSize, SERIALIZABLEXACT::prepareSeqNo, RWConflictDataSize, RWConflictPoolHeaderDataSize, ScratchTargetTagHash, SERIALIZABLEXACT::SeqNo, SetInvalidVirtualTransactionId, ShmemAlloc(), ShmemInitHash(), ShmemInitStruct(), SHMQueueInit(), SHMQueueInsertBefore(), PredXactListElementData::sxact, SXACT_FLAG_COMMITTED, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SERIALIZABLEXACT::topXid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, and SERIALIZABLEXACT::xmin.

Referenced by CreateSharedMemoryAndSemaphores().

1081 {
1082  HASHCTL info;
1083  long max_table_size;
1084  Size requestSize;
1085  bool found;
1086 
1087 #ifndef EXEC_BACKEND
1089 #endif
1090 
1091  /*
1092  * Compute size of predicate lock target hashtable. Note these
1093  * calculations must agree with PredicateLockShmemSize!
1094  */
1095  max_table_size = NPREDICATELOCKTARGETENTS();
1096 
1097  /*
1098  * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1099  * per-predicate-lock-target information.
1100  */
1101  MemSet(&info, 0, sizeof(info));
1102  info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1103  info.entrysize = sizeof(PREDICATELOCKTARGET);
1105 
1106  PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1107  max_table_size,
1108  max_table_size,
1109  &info,
1110  HASH_ELEM | HASH_BLOBS |
1112 
1113  /*
1114  * Reserve a dummy entry in the hash table; we use it to make sure there's
1115  * always one entry available when we need to split or combine a page,
1116  * because running out of space there could mean aborting a
1117  * non-serializable transaction.
1118  */
1119  if (!IsUnderPostmaster)
1120  {
1122  HASH_ENTER, &found);
1123  Assert(!found);
1124  }
1125 
1126  /* Pre-calculate the hash and partition lock of the scratch entry */
1129 
1130  /*
1131  * Allocate hash table for PREDICATELOCK structs. This stores per
1132  * xact-lock-of-a-target information.
1133  */
1134  MemSet(&info, 0, sizeof(info));
1135  info.keysize = sizeof(PREDICATELOCKTAG);
1136  info.entrysize = sizeof(PREDICATELOCK);
1137  info.hash = predicatelock_hash;
1139 
1140  /* Assume an average of 2 xacts per target */
1141  max_table_size *= 2;
1142 
1143  PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1144  max_table_size,
1145  max_table_size,
1146  &info,
1149 
1150  /*
1151  * Compute size for serializable transaction hashtable. Note these
1152  * calculations must agree with PredicateLockShmemSize!
1153  */
1154  max_table_size = (MaxBackends + max_prepared_xacts);
1155 
1156  /*
1157  * Allocate a list to hold information on transactions participating in
1158  * predicate locking.
1159  *
1160  * Assume an average of 10 predicate locking transactions per backend.
1161  * This allows aggressive cleanup while detail is present before data must
1162  * be summarized for storage in SLRU and the "dummy" transaction.
1163  */
1164  max_table_size *= 10;
1165 
1166  PredXact = ShmemInitStruct("PredXactList",
1168  &found);
1169  Assert(found == IsUnderPostmaster);
1170  if (!found)
1171  {
1172  int i;
1173 
1182  requestSize = mul_size((Size) max_table_size,
1184  PredXact->element = ShmemAlloc(requestSize);
1185  /* Add all elements to available list, clean. */
1186  memset(PredXact->element, 0, requestSize);
1187  for (i = 0; i < max_table_size; i++)
1188  {
1190  LWTRANCHE_SXACT);
1192  &(PredXact->element[i].link));
1193  }
1209  }
1210  /* This never changes, so let's keep a local copy. */
1212 
1213  /*
1214  * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1215  * information for serializable transactions which have accessed data.
1216  */
1217  MemSet(&info, 0, sizeof(info));
1218  info.keysize = sizeof(SERIALIZABLEXIDTAG);
1219  info.entrysize = sizeof(SERIALIZABLEXID);
1220 
1221  SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1222  max_table_size,
1223  max_table_size,
1224  &info,
1225  HASH_ELEM | HASH_BLOBS |
1226  HASH_FIXED_SIZE);
1227 
1228  /*
1229  * Allocate space for tracking rw-conflicts in lists attached to the
1230  * transactions.
1231  *
1232  * Assume an average of 5 conflicts per transaction. Calculations suggest
1233  * that this will prevent resource exhaustion in even the most pessimal
1234  * loads up to max_connections = 200 with all 200 connections pounding the
1235  * database with serializable transactions. Beyond that, there may be
1236  * occasional transactions canceled when trying to flag conflicts. That's
1237  * probably OK.
1238  */
1239  max_table_size *= 5;
1240 
1241  RWConflictPool = ShmemInitStruct("RWConflictPool",
1243  &found);
1244  Assert(found == IsUnderPostmaster);
1245  if (!found)
1246  {
1247  int i;
1248 
1250  requestSize = mul_size((Size) max_table_size,
1252  RWConflictPool->element = ShmemAlloc(requestSize);
1253  /* Add all elements to available list, clean. */
1254  memset(RWConflictPool->element, 0, requestSize);
1255  for (i = 0; i < max_table_size; i++)
1256  {
1258  &(RWConflictPool->element[i].outLink));
1259  }
1260  }
1261 
1262  /*
1263  * Create or attach to the header for the list of finished serializable
1264  * transactions.
1265  */
1267  ShmemInitStruct("FinishedSerializableTransactions",
1268  sizeof(SHM_QUEUE),
1269  &found);
1270  Assert(found == IsUnderPostmaster);
1271  if (!found)
1273 
1274  /*
1275  * Initialize the SLRU storage for old committed serializable
1276  * transactions.
1277  */
1278  OldSerXidInit();
1279 }
TransactionId finishedBefore
#define PredXactListDataSize
struct SERIALIZABLEXID SERIALIZABLEXID
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
#define HASH_ELEM
Definition: hsearch.h:87
#define NPREDICATELOCKTARGETENTS()
Definition: predicate.c:259
static PredXactList PredXact
Definition: predicate.c:379
TransactionId SxactGlobalXmin
struct SERIALIZABLEXIDTAG SERIALIZABLEXIDTAG
struct PREDICATELOCKTARGET PREDICATELOCKTARGET
Size entrysize
Definition: hsearch.h:73
static uint32 predicatelock_hash(const void *key, Size keysize)
Definition: predicate.c:1347
static HTAB * SerializableXidHash
Definition: predicate.c:391
#define MemSet(start, val, len)
Definition: c.h:971
static void OldSerXidInit(void)
Definition: predicate.c:814
void * ShmemAlloc(Size size)
Definition: shmem.c:161
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
#define SXACT_FLAG_COMMITTED
#define FirstNormalSerCommitSeqNo
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:908
#define HASH_PARTITION
Definition: hsearch.h:83
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
SHM_QUEUE possibleUnsafeConflicts
static HTAB * PredicateLockHash
Definition: predicate.c:393
int max_prepared_xacts
Definition: twophase.c:117
static RWConflictPoolHeader RWConflictPool
Definition: predicate.c:385
struct PREDICATELOCK PREDICATELOCK
long num_partitions
Definition: hsearch.h:67
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:392
struct PREDICATELOCKTAG PREDICATELOCKTAG
int MaxBackends
Definition: globals.c:135
#define RWConflictDataSize
VirtualTransactionId vxid
bool IsUnderPostmaster
Definition: globals.c:109
#define InvalidTransactionId
Definition: transam.h:31
SerCommitSeqNo lastCommitBeforeSnapshot
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:679
SerCommitSeqNo commitSeqNo
#define RWConflictPoolHeaderDataSize
SerCommitSeqNo HavePartialClearedThrough
#define HASH_BLOBS
Definition: hsearch.h:88
Size mul_size(Size s1, Size s2)
Definition: shmem.c:515
SerCommitSeqNo CanPartialClearThrough
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
Size keysize
Definition: hsearch.h:72
#define Assert(condition)
Definition: c.h:738
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:76
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
SerCommitSeqNo prepareSeqNo
size_t Size
Definition: c.h:466
SerCommitSeqNo LastSxactCommitSeqNo
SERIALIZABLEXACT * OldCommittedSxact
#define HASH_FIXED_SIZE
Definition: hsearch.h:96
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:357
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
union SERIALIZABLEXACT::@107 SeqNo
int i
static const PREDICATELOCKTARGETTAG ScratchTargetTag
Definition: predicate.c:401
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:337
static SHM_QUEUE * FinishedSerializableTransactions
Definition: predicate.c:394
static uint32 ScratchTargetTagHash
Definition: predicate.c:402
static LWLock * ScratchPartitionLock
Definition: predicate.c:403
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:580
PredXactListElement element
#define PredXactListElementDataSize
HashValueFunc hash
Definition: hsearch.h:74
#define HASH_FUNCTION
Definition: hsearch.h:89
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:121

◆ MaxPredicateChildLocks()

static int MaxPredicateChildLocks ( const PREDICATELOCKTARGETTAG tag)
static

Definition at line 2212 of file predicate.c.

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().

2213 {
2214  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2215  {
2216  case PREDLOCKTAG_RELATION:
2221 
2222  case PREDLOCKTAG_PAGE:
2224 
2225  case PREDLOCKTAG_TUPLE:
2226 
2227  /*
2228  * not reachable: nothing is finer-granularity than a tuple, so we
2229  * should never try to promote to it.
2230  */
2231  Assert(false);
2232  return 0;
2233  }
2234 
2235  /* not reachable */
2236  Assert(false);
2237  return 0;
2238 }
int max_predicate_locks_per_xact
Definition: predicate.c:366
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define Assert(condition)
Definition: c.h:738
int max_predicate_locks_per_relation
Definition: predicate.c:367
int max_predicate_locks_per_page
Definition: predicate.c:368

◆ NextPredXact()

static SERIALIZABLEXACT * NextPredXact ( SERIALIZABLEXACT sxact)
static

Definition at line 627 of file predicate.c.

References PredXactListData::activeList, Assert, PredXactListElementData::link, offsetof, ShmemAddrIsValid(), SHMQueueNext(), and PredXactListElementData::sxact.

Referenced by GetSafeSnapshotBlockingPids(), GetSerializableTransactionSnapshotInt(), and SetNewSxactGlobalXmin().

628 {
629  PredXactListElement ptle;
630 
631  Assert(ShmemAddrIsValid(sxact));
632 
633  ptle = (PredXactListElement)
634  (((char *) sxact)
637  ptle = (PredXactListElement)
639  &ptle->link,
641  if (!ptle)
642  return NULL;
643 
644  return &ptle->sxact;
645 }
static PredXactList PredXact
Definition: predicate.c:379
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
bool ShmemAddrIsValid(const void *addr)
Definition: shmem.c:283
#define Assert(condition)
Definition: c.h:738
struct PredXactListElementData * PredXactListElement
#define offsetof(type, field)
Definition: c.h:661

◆ OldSerXidAdd()

static void OldSerXidAdd ( TransactionId  xid,
SerCommitSeqNo  minConflictCommitSeqNo 
)
static

Definition at line 852 of file predicate.c.

References Assert, OldSerXidControlData::headPage, OldSerXidControlData::headXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), OldSerXidNextPage, OldSerXidPage, OldSerXidPagePrecedesLogically(), OldSerXidSlruCtl, OldSerXidValue, SimpleLruReadPage(), SimpleLruZeroPage(), OldSerXidControlData::tailXid, TransactionIdFollows(), and TransactionIdIsValid.

Referenced by SummarizeOldestCommittedSxact().

853 {
854  TransactionId tailXid;
855  int targetPage;
856  int slotno;
857  int firstZeroPage;
858  bool isNewPage;
859 
861 
862  targetPage = OldSerXidPage(xid);
863 
864  LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);
865 
866  /*
867  * If no serializable transactions are active, there shouldn't be anything
868  * to push out to the SLRU. Hitting this assert would mean there's
869  * something wrong with the earlier cleanup logic.
870  */
871  tailXid = oldSerXidControl->tailXid;
872  Assert(TransactionIdIsValid(tailXid));
873 
874  /*
875  * If the SLRU is currently unused, zero out the whole active region from
876  * tailXid to headXid before taking it into use. Otherwise zero out only
877  * any new pages that enter the tailXid-headXid range as we advance
878  * headXid.
879  */
880  if (oldSerXidControl->headPage < 0)
881  {
882  firstZeroPage = OldSerXidPage(tailXid);
883  isNewPage = true;
884  }
885  else
886  {
887  firstZeroPage = OldSerXidNextPage(oldSerXidControl->headPage);
889  targetPage);
890  }
891 
894  oldSerXidControl->headXid = xid;
895  if (isNewPage)
896  oldSerXidControl->headPage = targetPage;
897 
898  if (isNewPage)
899  {
900  /* Initialize intervening pages. */
901  while (firstZeroPage != targetPage)
902  {
903  (void) SimpleLruZeroPage(OldSerXidSlruCtl, firstZeroPage);
904  firstZeroPage = OldSerXidNextPage(firstZeroPage);
905  }
906  slotno = SimpleLruZeroPage(OldSerXidSlruCtl, targetPage);
907  }
908  else
909  slotno = SimpleLruReadPage(OldSerXidSlruCtl, targetPage, true, xid);
910 
911  OldSerXidValue(slotno, xid) = minConflictCommitSeqNo;
912  OldSerXidSlruCtl->shared->page_dirty[slotno] = true;
913 
914  LWLockRelease(OldSerXidLock);
915 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:513
#define OldSerXidPage(xid)
Definition: predicate.c:338
#define OldSerXidSlruCtl
Definition: predicate.c:321
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:377
TransactionId headXid
Definition: predicate.c:343
#define Assert(condition)
Definition: c.h:738
static bool OldSerXidPagePrecedesLogically(int p, int q)
Definition: predicate.c:791
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
static OldSerXidControl oldSerXidControl
Definition: predicate.c:349
#define OldSerXidValue(slotno, xid)
Definition: predicate.c:334
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:262
#define OldSerXidNextPage(page)
Definition: predicate.c:332
TransactionId tailXid
Definition: predicate.c:344

◆ OldSerXidGetMinConflictCommitSeqNo()

static SerCommitSeqNo OldSerXidGetMinConflictCommitSeqNo ( TransactionId  xid)
static

Definition at line 923 of file predicate.c.

References Assert, OldSerXidControlData::headXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), OldSerXidPage, OldSerXidSlruCtl, OldSerXidValue, SimpleLruReadPage_ReadOnly(), OldSerXidControlData::tailXid, TransactionIdFollows(), TransactionIdIsValid, TransactionIdPrecedes(), and val.

Referenced by CheckForSerializableConflictOut().

924 {
925  TransactionId headXid;
926  TransactionId tailXid;
928  int slotno;
929 
931 
932  LWLockAcquire(OldSerXidLock, LW_SHARED);
933  headXid = oldSerXidControl->headXid;
934  tailXid = oldSerXidControl->tailXid;
935  LWLockRelease(OldSerXidLock);
936 
937  if (!TransactionIdIsValid(headXid))
938  return 0;
939 
940  Assert(TransactionIdIsValid(tailXid));
941 
942  if (TransactionIdPrecedes(xid, tailXid)
943  || TransactionIdFollows(xid, headXid))
944  return 0;
945 
946  /*
947  * The following function must be called without holding OldSerXidLock,
948  * but will return with that lock held, which must then be released.
949  */
951  OldSerXidPage(xid), xid);
952  val = OldSerXidValue(slotno, xid);
953  LWLockRelease(OldSerXidLock);
954  return val;
955 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:513
#define OldSerXidPage(xid)
Definition: predicate.c:338
#define OldSerXidSlruCtl
Definition: predicate.c:321
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
TransactionId headXid
Definition: predicate.c:343
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:477
uint64 SerCommitSeqNo
#define Assert(condition)
Definition: c.h:738
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
static OldSerXidControl oldSerXidControl
Definition: predicate.c:349
#define OldSerXidValue(slotno, xid)
Definition: predicate.c:334
#define TransactionIdIsValid(xid)
Definition: transam.h:41
long val
Definition: informix.c:664
TransactionId tailXid
Definition: predicate.c:344

◆ OldSerXidInit()

static void OldSerXidInit ( void  )
static

Definition at line 814 of file predicate.c.

References Assert, OldSerXidControlData::headPage, OldSerXidControlData::headXid, InvalidTransactionId, IsUnderPostmaster, LWTRANCHE_OLDSERXID_BUFFERS, NUM_OLDSERXID_BUFFERS, OldSerXidPagePrecedesLogically(), OldSerXidSlruCtl, ShmemInitStruct(), SimpleLruInit(), and OldSerXidControlData::tailXid.

Referenced by InitPredicateLocks().

815 {
816  bool found;
817 
818  /*
819  * Set up SLRU management of the pg_serial data.
820  */
822  SimpleLruInit(OldSerXidSlruCtl, "oldserxid",
823  NUM_OLDSERXID_BUFFERS, 0, OldSerXidLock, "pg_serial",
825  /* Override default assumption that writes should be fsync'd */
826  OldSerXidSlruCtl->do_fsync = false;
827 
828  /*
829  * Create or attach to the OldSerXidControl structure.
830  */
832  ShmemInitStruct("OldSerXidControlData", sizeof(OldSerXidControlData), &found);
833 
834  Assert(found == IsUnderPostmaster);
835  if (!found)
836  {
837  /*
838  * Set control information to reflect empty SLRU.
839  */
843  }
844 }
struct OldSerXidControlData * OldSerXidControl
Definition: predicate.c:347
#define NUM_OLDSERXID_BUFFERS
Definition: predicate.h:31
#define OldSerXidSlruCtl
Definition: predicate.c:321
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:392
bool IsUnderPostmaster
Definition: globals.c:109
#define InvalidTransactionId
Definition: transam.h:31
TransactionId headXid
Definition: predicate.c:343
#define Assert(condition)
Definition: c.h:738
static bool OldSerXidPagePrecedesLogically(int p, int q)
Definition: predicate.c:791
static OldSerXidControl oldSerXidControl
Definition: predicate.c:349
TransactionId tailXid
Definition: predicate.c:344
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id)
Definition: slru.c:164

◆ OldSerXidPagePrecedesLogically()

static bool OldSerXidPagePrecedesLogically ( int  p,
int  q 
)
static

Definition at line 791 of file predicate.c.

References Assert, and OLDSERXID_MAX_PAGE.

Referenced by OldSerXidAdd(), and OldSerXidInit().

792 {
793  int diff;
794 
795  /*
796  * We have to compare modulo (OLDSERXID_MAX_PAGE+1)/2. Both inputs should
797  * be in the range 0..OLDSERXID_MAX_PAGE.
798  */
799  Assert(p >= 0 && p <= OLDSERXID_MAX_PAGE);
800  Assert(q >= 0 && q <= OLDSERXID_MAX_PAGE);
801 
802  diff = p - q;
803  if (diff >= ((OLDSERXID_MAX_PAGE + 1) / 2))
804  diff -= OLDSERXID_MAX_PAGE + 1;
805  else if (diff < -((int) (OLDSERXID_MAX_PAGE + 1) / 2))
806  diff += OLDSERXID_MAX_PAGE + 1;
807  return diff < 0;
808 }
#define OLDSERXID_MAX_PAGE
Definition: predicate.c:330
#define Assert(condition)
Definition: c.h:738

◆ OldSerXidSetActiveSerXmin()

static void OldSerXidSetActiveSerXmin ( TransactionId  xid)
static

Definition at line 964 of file predicate.c.

References Assert, OldSerXidControlData::headPage, OldSerXidControlData::headXid, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), RecoveryInProgress(), OldSerXidControlData::tailXid, TransactionIdFollows(), TransactionIdIsValid, and TransactionIdPrecedes().

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

965 {
966  LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);
967 
968  /*
969  * When no sxacts are active, nothing overlaps, set the xid values to
970  * invalid to show that there are no valid entries. Don't clear headPage,
971  * though. A new xmin might still land on that page, and we don't want to
972  * repeatedly zero out the same page.
973  */
974  if (!TransactionIdIsValid(xid))
975  {
978  LWLockRelease(OldSerXidLock);
979  return;
980  }
981 
982  /*
983  * When we're recovering prepared transactions, the global xmin might move
984  * backwards depending on the order they're recovered. Normally that's not
985  * OK, but during recovery no serializable transactions will commit, so
986  * the SLRU is empty and we can get away with it.
987  */
988  if (RecoveryInProgress())
989  {
993  {
994  oldSerXidControl->tailXid = xid;
995  }
996  LWLockRelease(OldSerXidLock);
997  return;
998  }
999 
1002 
1003  oldSerXidControl->tailXid = xid;
1004 
1005  LWLockRelease(OldSerXidLock);
1006 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
bool RecoveryInProgress(void)
Definition: xlog.c:8043
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
#define InvalidTransactionId
Definition: transam.h:31
TransactionId headXid
Definition: predicate.c:343
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define Assert(condition)
Definition: c.h:738
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
static OldSerXidControl oldSerXidControl
Definition: predicate.c:349
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId tailXid
Definition: predicate.c:344

◆ OnConflict_CheckForSerializationFailure()

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

Definition at line 4584 of file predicate.c.

References Assert, SERIALIZABLEXACT::commitSeqNo, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LWLockHeldByMe(), LWLockRelease(), offsetof, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::prepareSeqNo, SERIALIZABLEXACT::SeqNo, SHMQueueNext(), SXACT_FLAG_DOOMED, SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, RWConflictData::sxactIn, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, RWConflictData::sxactOut, and SERIALIZABLEXACT::topXid.

Referenced by FlagRWConflict().

4586 {
4587  bool failure;
4588  RWConflict conflict;
4589 
4590  Assert(LWLockHeldByMe(SerializableXactHashLock));
4591 
4592  failure = false;
4593 
4594  /*------------------------------------------------------------------------
4595  * Check for already-committed writer with rw-conflict out flagged
4596  * (conflict-flag on W means that T2 committed before W):
4597  *
4598  * R ------> W ------> T2
4599  * rw rw
4600  *
4601  * That is a dangerous structure, so we must abort. (Since the writer
4602  * has already committed, we must be the reader)
4603  *------------------------------------------------------------------------
4604  */
4605  if (SxactIsCommitted(writer)
4606  && (SxactHasConflictOut(writer) || SxactHasSummaryConflictOut(writer)))
4607  failure = true;
4608 
4609  /*------------------------------------------------------------------------
4610  * Check whether the writer has become a pivot with an out-conflict
4611  * committed transaction (T2), and T2 committed first:
4612  *
4613  * R ------> W ------> T2
4614  * rw rw
4615  *
4616  * Because T2 must've committed first, there is no anomaly if:
4617  * - the reader committed before T2
4618  * - the writer committed before T2
4619  * - the reader is a READ ONLY transaction and the reader was concurrent
4620  * with T2 (= reader acquired its snapshot before T2 committed)
4621  *
4622  * We also handle the case that T2 is prepared but not yet committed
4623  * here. In that case T2 has already checked for conflicts, so if it
4624  * commits first, making the above conflict real, it's too late for it
4625  * to abort.
4626  *------------------------------------------------------------------------
4627  */
4628  if (!failure)
4629  {
4630  if (SxactHasSummaryConflictOut(writer))
4631  {
4632  failure = true;
4633  conflict = NULL;
4634  }
4635  else
4636  conflict = (RWConflict)
4637  SHMQueueNext(&writer->outConflicts,
4638  &writer->outConflicts,
4639  offsetof(RWConflictData, outLink));
4640  while (conflict)
4641  {
4642  SERIALIZABLEXACT *t2 = conflict->sxactIn;
4643 
4644  if (SxactIsPrepared(t2)
4645  && (!SxactIsCommitted(reader)
4646  || t2->prepareSeqNo <= reader->commitSeqNo)
4647  && (!SxactIsCommitted(writer)
4648  || t2->prepareSeqNo <= writer->commitSeqNo)
4649  && (!SxactIsReadOnly(reader)
4650  || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
4651  {
4652  failure = true;
4653  break;
4654  }
4655  conflict = (RWConflict)
4656  SHMQueueNext(&writer->outConflicts,
4657  &conflict->outLink,
4658  offsetof(RWConflictData, outLink));
4659  }
4660  }
4661 
4662  /*------------------------------------------------------------------------
4663  * Check whether the reader has become a pivot with a writer
4664  * that's committed (or prepared):
4665  *
4666  * T0 ------> R ------> W
4667  * rw rw
4668  *
4669  * Because W must've committed first for an anomaly to occur, there is no
4670  * anomaly if:
4671  * - T0 committed before the writer
4672  * - T0 is READ ONLY, and overlaps the writer
4673  *------------------------------------------------------------------------
4674  */
4675  if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
4676  {
4677  if (SxactHasSummaryConflictIn(reader))
4678  {
4679  failure = true;
4680  conflict = NULL;
4681  }
4682  else
4683  conflict = (RWConflict)
4684  SHMQueueNext(&reader->inConflicts,
4685  &reader->inConflicts,
4686  offsetof(RWConflictData, inLink));
4687  while (conflict)
4688  {
4689  SERIALIZABLEXACT *t0 = conflict->sxactOut;
4690 
4691  if (!SxactIsDoomed(t0)
4692  && (!SxactIsCommitted(t0)
4693  || t0->commitSeqNo >= writer->prepareSeqNo)
4694  && (!SxactIsReadOnly(t0)
4695  || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
4696  {
4697  failure = true;
4698  break;
4699  }
4700  conflict = (RWConflict)
4701  SHMQueueNext(&reader->inConflicts,
4702  &conflict->inLink,
4703  offsetof(RWConflictData, inLink));
4704  }
4705  }
4706 
4707  if (failure)
4708  {
4709  /*
4710  * We have to kill a transaction to avoid a possible anomaly from
4711  * occurring. If the writer is us, we can just ereport() to cause a
4712  * transaction abort. Otherwise we flag the writer for termination,
4713  * causing it to abort when it tries to commit. However, if the writer
4714  * is a prepared transaction, already prepared, we can't abort it
4715  * anymore, so we have to kill the reader instead.
4716  */
4717  if (MySerializableXact == writer)
4718  {
4719  LWLockRelease(SerializableXactHashLock);
4720  ereport(ERROR,
4721  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4722  errmsg("could not serialize access due to read/write dependencies among transactions"),
4723  errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
4724  errhint("The transaction might succeed if retried.")));
4725  }
4726  else if (SxactIsPrepared(writer))
4727  {
4728  LWLockRelease(SerializableXactHashLock);
4729 
4730  /* if we're not the writer, we have to be the reader */
4731  Assert(MySerializableXact == reader);
4732  ereport(ERROR,
4733  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4734  errmsg("could not serialize access due to read/write dependencies among transactions"),
4735  errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
4736  errhint("The transaction might succeed if retried.")));
4737  }
4738  writer->flags |= SXACT_FLAG_DOOMED;
4739  }
4740 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
int errhint(const char *fmt,...)
Definition: elog.c:1071
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:277
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1843
struct RWConflictData * RWConflict
int errcode(int sqlerrcode)
Definition: elog.c:610
#define SxactIsPrepared(sxact)
Definition: predicate.c:273
int errdetail_internal(const char *fmt,...)
Definition: elog.c:984
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
SERIALIZABLEXACT * sxactIn
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define ERROR
Definition: elog.h:43
SerCommitSeqNo lastCommitBeforeSnapshot
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:278
SerCommitSeqNo commitSeqNo
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define ereport(elevel,...)
Definition: elog.h:144
#define SXACT_FLAG_DOOMED
#define SxactHasConflictOut(sxact)
Definition: predicate.c:284
#define Assert(condition)
Definition: c.h:738
SerCommitSeqNo prepareSeqNo
int errmsg(const char *fmt,...)
Definition: elog.c:824
union SERIALIZABLEXACT::@107 SeqNo
#define SxactIsCommitted(sxact)
Definition: predicate.c:272
#define offsetof(type, field)
Definition: c.h:661
SERIALIZABLEXACT * sxactOut

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

Definition at line 1921 of file predicate.c.

References RelFileNode::dbNode, HASH_FIND, hash_search_with_hash_value(), LW_SHARED, LWLockAcquire(), LWLockRelease(), PredicateLockHashPartitionLock, PredicateLockTargetTagHashCode, RelationData::rd_id, RelationData::rd_node, and SET_PREDICATELOCKTARGETTAG_PAGE.

1922 {
1923  PREDICATELOCKTARGETTAG targettag;
1924  uint32 targettaghash;
1925  LWLock *partitionLock;
1926  PREDICATELOCKTARGET *target;
1927 
1929  relation->rd_node.dbNode,
1930  relation->rd_id,
1931  blkno);
1932 
1933  targettaghash = PredicateLockTargetTagHashCode(&targettag);
1934  partitionLock = PredicateLockHashPartitionLock(targettaghash);
1935  LWLockAcquire(partitionLock, LW_SHARED);
1936  target = (PREDICATELOCKTARGET *)
1938  &targettag, targettaghash,
1939  HASH_FIND, NULL);
1940  LWLockRelease(partitionLock);
1941 
1942  return (target != NULL);
1943 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:921
Definition: lwlock.h:32
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
unsigned int uint32
Definition: c.h:367
Oid rd_id
Definition: rel.h:111
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
RelFileNode rd_node
Definition: rel.h:55
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123

◆ PostPrepare_PredicateLocks()

void PostPrepare_PredicateLocks ( TransactionId  xid)

Definition at line 4929 of file predicate.c.

References Assert, hash_destroy(), InvalidSerializableXact, MyXactDidWrite, SERIALIZABLEXACT::pid, and SxactIsPrepared.

Referenced by PrepareTransaction().

4930 {
4932  return;
4933 
4935 
4936  MySerializableXact->pid = 0;
4937 
4939  LocalPredicateLockHash = NULL;
4940 
4942  MyXactDidWrite = false;
4943 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:816
#define SxactIsPrepared(sxact)
Definition: predicate.c:273
#define InvalidSerializableXact
#define Assert(condition)
Definition: c.h:738
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409
static bool MyXactDidWrite
Definition: predicate.c:417

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4759 of file predicate.c.

References Assert, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, InvalidSerializableXact, IsolationIsSerializable, PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), offsetof, SERIALIZABLEXACT::prepareSeqNo, SHMQueueNext(), SXACT_FLAG_DOOMED, SXACT_FLAG_PREPARED, SxactIsCommitted, SxactIsDoomed, SxactIsPartiallyReleased, SxactIsPrepared, SxactIsReadOnly, and RWConflictData::sxactOut.

Referenced by CommitTransaction(), and PrepareTransaction().

4760 {
4761  RWConflict nearConflict;
4762 
4764  return;
4765 
4767 
4768  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4769 
4770  /* Check if someone else has already decided that we need to die */
4772  {
4774  LWLockRelease(SerializableXactHashLock);
4775  ereport(ERROR,
4776  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4777  errmsg("could not serialize access due to read/write dependencies among transactions"),
4778  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4779  errhint("The transaction might succeed if retried.")));
4780  }
4781 
4782  nearConflict = (RWConflict)
4785  offsetof(RWConflictData, inLink));
4786  while (nearConflict)
4787  {
4788  if (!SxactIsCommitted(nearConflict->sxactOut)
4789  && !SxactIsDoomed(nearConflict->sxactOut))
4790  {
4791  RWConflict farConflict;
4792 
4793  farConflict = (RWConflict)
4794  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4795  &nearConflict->sxactOut->inConflicts,
4796  offsetof(RWConflictData, inLink));
4797  while (farConflict)
4798  {
4799  if (farConflict->sxactOut == MySerializableXact
4800  || (!SxactIsCommitted(farConflict->sxactOut)
4801  && !SxactIsReadOnly(farConflict->sxactOut)
4802  && !SxactIsDoomed(farConflict->sxactOut)))
4803  {
4804  /*
4805  * Normally, we kill the pivot transaction to make sure we
4806  * make progress if the failing transaction is retried.
4807  * However, we can't kill it if it's already prepared, so
4808  * in that case we commit suicide instead.
4809  */
4810  if (SxactIsPrepared(nearConflict->sxactOut))
4811  {
4812  LWLockRelease(SerializableXactHashLock);
4813  ereport(ERROR,
4814  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4815  errmsg("could not serialize access due to read/write dependencies among transactions"),
4816  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4817  errhint("The transaction might succeed if retried.")));
4818  }
4819  nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4820  break;
4821  }
4822  farConflict = (RWConflict)
4823  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4824  &farConflict->inLink,
4825  offsetof(RWConflictData, inLink));
4826  }
4827  }
4828 
4829  nearConflict = (RWConflict)
4831  &nearConflict->inLink,
4832  offsetof(RWConflictData, inLink));
4833  }
4834 
4837 
4838  LWLockRelease(SerializableXactHashLock);
4839 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
int errhint(const char *fmt,...)
Definition: elog.c:1071
static PredXactList PredXact
Definition: predicate.c:379
struct RWConflictData * RWConflict
int errcode(int sqlerrcode)
Definition: elog.c:610
#define SxactIsPrepared(sxact)
Definition: predicate.c:273
int errdetail_internal(const char *fmt,...)
Definition: elog.c:984
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define ERROR
Definition: elog.h:43
#define InvalidSerializableXact
#define SXACT_FLAG_PREPARED
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define ereport(elevel,...)
Definition: elog.h:144
#define SXACT_FLAG_DOOMED
#define Assert(condition)
Definition: c.h:738
SerCommitSeqNo prepareSeqNo
SerCommitSeqNo LastSxactCommitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1123
#define SxactIsPartiallyReleased(sxact)
Definition: predicate.c:288
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define IsolationIsSerializable()
Definition: xact.h:52
#define SxactIsCommitted(sxact)
Definition: predicate.c:272
#define offsetof(type, field)
Definition: c.h:661
SERIALIZABLEXACT * sxactOut

◆ predicatelock_hash()

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

Definition at line 1347 of file predicate.c.

References Assert, PREDICATELOCKTAG::myTarget, PredicateLockHashCodeFromTargetHashCode, PredicateLockTargetTagHashCode, and PREDICATELOCKTARGET::tag.

Referenced by InitPredicateLocks().

1348 {
1349  const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
1350  uint32 targethash;
1351 
1352  Assert(keysize == sizeof(PREDICATELOCKTAG));
1353 
1354  /* Look into the associated target object, and compute its hash code */
1355  targethash = PredicateLockTargetTagHashCode(&predicatelocktag->myTarget->tag);
1356 
1357  return PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash);
1358 }
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
unsigned int uint32
Definition: c.h:367
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:738
PREDICATELOCKTARGET * myTarget

◆ predicatelock_twophase_recover()

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

Definition at line 4978 of file predicate.c.

References Assert, VirtualTransactionId::backendId, SERIALIZABLEXACT::commitSeqNo, CreatePredicateLock(), CreatePredXact(), TwoPhasePredicateRecord::data, ereport, errcode(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, SERIALIZABLEXACT::flags, TwoPhasePredicateXactRecord::flags, HASH_ENTER, HASH_FIND, hash_search(), SERIALIZABLEXACT::inConflicts, InvalidBackendId, InvalidSerCommitSeqNo, InvalidSerializableXact, InvalidTransactionId, SERIALIZABLEXACT::lastCommitBeforeSnapshot, VirtualTransactionId::localTransactionId, TwoPhasePredicateRecord::lockRecord, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_prepared_xacts, MaxBackends, SERIALIZABLEXID::myXact, OldSerXidSetActiveSerXmin(), SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, SERIALIZABLEXACT::prepareSeqNo, RecoverySerCommitSeqNo, SERIALIZABLEXACT::SeqNo, SHMQueueElemInit(), SHMQueueInit(), 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.

4980 {
4981  TwoPhasePredicateRecord *record;
4982 
4983  Assert(len == sizeof(TwoPhasePredicateRecord));
4984 
4985  record = (TwoPhasePredicateRecord *) recdata;
4986 
4987  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
4988  (record->type == TWOPHASEPREDICATERECORD_LOCK));
4989 
4990  if (record->type == TWOPHASEPREDICATERECORD_XACT)
4991  {
4992  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4993  TwoPhasePredicateXactRecord *xactRecord;
4994  SERIALIZABLEXACT *sxact;
4995  SERIALIZABLEXID *sxid;
4996  SERIALIZABLEXIDTAG sxidtag;
4997  bool found;
4998 
4999  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
5000 
5001  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
5002  sxact = CreatePredXact();
5003  if (!sxact)
5004  ereport(ERROR,
5005  (errcode(ERRCODE_OUT_OF_MEMORY),
5006  errmsg("out of shared memory")));
5007 
5008  /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
5009  sxact->vxid.backendId = InvalidBackendId;
5011  sxact->pid = 0;
5012 
5013  /* a prepared xact hasn't committed yet */
5017 
5019 
5020  /*
5021  * Don't need to track this; no transactions running at the time the
5022  * recovered xact started are still active, except possibly other
5023  * prepared xacts and we don't care whether those are RO_SAFE or not.
5024  */
5026 
5027  SHMQueueInit(&(sxact->predicateLocks));
5028  SHMQueueElemInit(&(sxact->finishedLink));
5029 
5030  sxact->topXid = xid;
5031  sxact->xmin = xactRecord->xmin;
5032  sxact->flags = xactRecord->flags;
5033  Assert(SxactIsPrepared(sxact));
5034  if (!SxactIsReadOnly(sxact))
5035  {
5039  }
5040 
5041  /*
5042  * We don't know whether the transaction had any conflicts or not, so
5043  * we'll conservatively assume that it had both a conflict in and a
5044  * conflict out, and represent that with the summary conflict flags.
5045  */
5046  SHMQueueInit(&(sxact->outConflicts));
5047  SHMQueueInit(&(sxact->inConflicts));
5050 
5051  /* Register the transaction's xid */
5052  sxidtag.xid = xid;
5054  &sxidtag,
5055  HASH_ENTER, &found);
5056  Assert(sxid != NULL);
5057  Assert(!found);
5058  sxid->myXact = (SERIALIZABLEXACT *) sxact;
5059 
5060  /*
5061  * Update global xmin. Note that this is a special case compared to
5062  * registering a normal transaction, because the global xmin might go
5063  * backwards. That's OK, because until recovery is over we're not
5064  * going to complete any transactions or create any non-prepared
5065  * transactions, so there's no danger of throwing away.
5066  */
5069  {
5070  PredXact->SxactGlobalXmin = sxact->xmin;
5073  }
5074  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
5075  {
5078  }
5079 
5080  LWLockRelease(SerializableXactHashLock);
5081  }
5082  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
5083  {
5084  /* Lock record. Recreate the PREDICATELOCK */
5085  TwoPhasePredicateLockRecord *lockRecord;
5086  SERIALIZABLEXID *sxid;
5087  SERIALIZABLEXACT *sxact;
5088  SERIALIZABLEXIDTAG sxidtag;
5089  uint32 targettaghash;
5090 
5091  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
5092  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
5093 
5094  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
5095  sxidtag.xid = xid;
5096  sxid = (SERIALIZABLEXID *)
5097  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
5098  LWLockRelease(SerializableXactHashLock);
5099 
5100  Assert(sxid != NULL);
5101  sxact = sxid->myXact;
5102  Assert(sxact != InvalidSerializableXact);
5103 
5104  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5105  }
5106 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
TransactionId finishedBefore
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2376
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
static PredXactList PredXact
Definition: predicate.c:379
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
TransactionId SxactGlobalXmin
int errcode(int sqlerrcode)
Definition: elog.c:610
static HTAB * SerializableXidHash
Definition: predicate.c:391
union TwoPhasePredicateRecord::@108 data
SERIALIZABLEXACT * myXact
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:908
#define SxactIsPrepared(sxact)
Definition: predicate.c:273
TwoPhasePredicateRecordType type
LocalTransactionId localTransactionId
Definition: lock.h:65
PREDICATELOCKTARGETTAG target
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1727
SHM_QUEUE possibleUnsafeConflicts
#define ERROR
Definition: elog.h:43
int max_prepared_xacts
Definition: twophase.c:117
TwoPhasePredicateXactRecord xactRecord
#define InvalidSerializableXact
int MaxBackends
Definition: globals.c:135
VirtualTransactionId vxid
#define InvalidTransactionId
Definition: transam.h:31
unsigned int uint32
Definition: c.h:367
uint32 LocalTransactionId
Definition: c.h:515
SerCommitSeqNo lastCommitBeforeSnapshot