PostgreSQL Source Code  git master
predicate.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.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 PredicateLockTuple (Relation relation, HeapTuple tuple, Snapshot snapshot)
 
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)
 
void CheckForSerializableConflictOut (bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
 
void CheckForSerializableConflictIn (Relation relation, HeapTuple tuple, Buffer buffer)
 
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 262 of file predicate.c.

Referenced by InitPredicateLocks(), and PredicateLockShmemSize().

◆ OLDSERXID_ENTRIESPERPAGE

#define OLDSERXID_ENTRIESPERPAGE   (OLDSERXID_PAGESIZE / OLDSERXID_ENTRYSIZE)

Definition at line 328 of file predicate.c.

◆ OLDSERXID_ENTRYSIZE

#define OLDSERXID_ENTRYSIZE   sizeof(SerCommitSeqNo)

Definition at line 327 of file predicate.c.

◆ OLDSERXID_MAX_PAGE

#define OLDSERXID_MAX_PAGE   (MaxTransactionId / OLDSERXID_ENTRIESPERPAGE)

Definition at line 333 of file predicate.c.

Referenced by OldSerXidPagePrecedesLogically().

◆ OLDSERXID_PAGESIZE

#define OLDSERXID_PAGESIZE   BLCKSZ

Definition at line 326 of file predicate.c.

◆ OldSerXidNextPage

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

Definition at line 335 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:327
#define OldSerXidSlruCtl
Definition: predicate.c:324
#define OLDSERXID_ENTRIESPERPAGE
Definition: predicate.c:328
unsigned int uint32
Definition: c.h:359
uint64 SerCommitSeqNo

Definition at line 337 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 254 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 288 of file predicate.c.

Referenced by GetSafeSnapshotBlockingPids(), and ReleasePredicateLocks().

◆ SxactIsDoomed

◆ SxactIsOnFinishedList

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

Definition at line 265 of file predicate.c.

Referenced by ReleaseOneSerializableXact(), and ReleasePredicateLocks().

◆ SxactIsPartiallyReleased

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

Definition at line 291 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 290 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 231 of file predicate.c.

Referenced by DeleteChildTargetLocks().

Typedef Documentation

◆ OldSerXidControl

Definition at line 350 of file predicate.c.

◆ OldSerXidControlData

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4906 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().

4907 {
4908  PREDICATELOCK *predlock;
4909  SERIALIZABLEXACT *sxact;
4910  TwoPhasePredicateRecord record;
4911  TwoPhasePredicateXactRecord *xactRecord;
4912  TwoPhasePredicateLockRecord *lockRecord;
4913 
4914  sxact = MySerializableXact;
4915  xactRecord = &(record.data.xactRecord);
4916  lockRecord = &(record.data.lockRecord);
4917 
4919  return;
4920 
4921  /* Generate an xact record for our SERIALIZABLEXACT */
4923  xactRecord->xmin = MySerializableXact->xmin;
4924  xactRecord->flags = MySerializableXact->flags;
4925 
4926  /*
4927  * Note that we don't include the list of conflicts in our out in the
4928  * statefile, because new conflicts can be added even after the
4929  * transaction prepares. We'll just make a conservative assumption during
4930  * recovery instead.
4931  */
4932 
4934  &record, sizeof(record));
4935 
4936  /*
4937  * Generate a lock record for each lock.
4938  *
4939  * To do this, we need to walk the predicate lock list in our sxact rather
4940  * than using the local predicate lock table because the latter is not
4941  * guaranteed to be accurate.
4942  */
4943  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
4944 
4945  /*
4946  * No need to take sxact->predicateLockListLock in parallel mode because
4947  * there cannot be any parallel workers running while we are preparing a
4948  * transaction.
4949  */
4951 
4952  predlock = (PREDICATELOCK *)
4953  SHMQueueNext(&(sxact->predicateLocks),
4954  &(sxact->predicateLocks),
4955  offsetof(PREDICATELOCK, xactLink));
4956 
4957  while (predlock != NULL)
4958  {
4960  lockRecord->target = predlock->tag.myTarget->tag;
4961 
4963  &record, sizeof(record));
4964 
4965  predlock = (PREDICATELOCK *)
4966  SHMQueueNext(&(sxact->predicateLocks),
4967  &(predlock->xactLink),
4968  offsetof(PREDICATELOCK, xactLink));
4969  }
4970 
4971  LWLockRelease(SerializablePredicateLockListLock);
4972 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
TwoPhasePredicateRecordType type
PREDICATELOCKTARGETTAG target
union TwoPhasePredicateRecord::@110 data
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1187
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define TWOPHASE_RM_PREDICATELOCK_ID
Definition: twophase_rmgr.h:28
TwoPhasePredicateXactRecord xactRecord
#define InvalidSerializableXact
#define IsParallelWorker()
Definition: parallel.h:60
bool ParallelContextActive(void)
Definition: parallel.c:944
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:733
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
TwoPhasePredicateLockRecord lockRecord
#define offsetof(type, field)
Definition: c.h:656
PREDICATELOCKTARGET * myTarget

◆ AttachSerializableXact()

void AttachSerializableXact ( SerializableXactHandle  handle)

Definition at line 5176 of file predicate.c.

References Assert, CreateLocalPredicateLockHash(), and InvalidSerializableXact.

Referenced by ParallelWorkerMain().

5177 {
5178 
5180 
5181  MySerializableXact = (SERIALIZABLEXACT *) handle;
5184 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
#define InvalidSerializableXact
#define Assert(condition)
Definition: c.h:733
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1855

◆ CheckAndPromotePredicateLockRequest()

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2252 of file predicate.c.

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

Referenced by PredicateLockAcquire().

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

◆ CheckForSerializableConflictIn()

void CheckForSerializableConflictIn ( Relation  relation,
HeapTuple  tuple,
Buffer  buffer 
)

Definition at line 4426 of file predicate.c.

References BufferGetBlockNumber(), BufferIsValid, CheckTargetForConflictsIn(), RelFileNode::dbNode, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, MyXactDidWrite, RelationData::rd_id, RelationData::rd_node, SerializationNeededForWrite(), SET_PREDICATELOCKTARGETTAG_PAGE, SET_PREDICATELOCKTARGETTAG_RELATION, SET_PREDICATELOCKTARGETTAG_TUPLE, SxactIsDoomed, and HeapTupleData::t_self.

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

4428 {
4429  PREDICATELOCKTARGETTAG targettag;
4430 
4431  if (!SerializationNeededForWrite(relation))
4432  return;
4433 
4434  /* Check if someone else has already decided that we need to die */
4436  ereport(ERROR,
4437  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4438  errmsg("could not serialize access due to read/write dependencies among transactions"),
4439  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4440  errhint("The transaction might succeed if retried.")));
4441 
4442  /*
4443  * We're doing a write which might cause rw-conflicts now or later.
4444  * Memorize that fact.
4445  */
4446  MyXactDidWrite = true;
4447 
4448  /*
4449  * It is important that we check for locks from the finest granularity to
4450  * the coarsest granularity, so that granularity promotion doesn't cause
4451  * us to miss a lock. The new (coarser) lock will be acquired before the
4452  * old (finer) locks are released.
4453  *
4454  * It is not possible to take and hold a lock across the checks for all
4455  * granularities because each target could be in a separate partition.
4456  */
4457  if (tuple != NULL)
4458  {
4460  relation->rd_node.dbNode,
4461  relation->rd_id,
4462  ItemPointerGetBlockNumber(&(tuple->t_self)),
4463  ItemPointerGetOffsetNumber(&(tuple->t_self)));
4464  CheckTargetForConflictsIn(&targettag);
4465  }
4466 
4467  if (BufferIsValid(buffer))
4468  {
4470  relation->rd_node.dbNode,
4471  relation->rd_id,
4472  BufferGetBlockNumber(buffer));
4473  CheckTargetForConflictsIn(&targettag);
4474  }
4475 
4477  relation->rd_node.dbNode,
4478  relation->rd_id);
4479  CheckTargetForConflictsIn(&targettag);
4480 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
int errhint(const char *fmt,...)
Definition: elog.c:1071
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4244
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
int errcode(int sqlerrcode)
Definition: elog.c:608
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:561
#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:278
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define ereport(elevel, rest)
Definition: elog.h:141
Oid rd_id
Definition: rel.h:85
RelFileNode rd_node
Definition: rel.h:54
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2613
int errmsg(const char *fmt,...)
Definition: elog.c:822
static bool MyXactDidWrite
Definition: predicate.c:420
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98

◆ CheckForSerializableConflictOut()

void CheckForSerializableConflictOut ( bool  visible,
Relation  relation,
HeapTuple  tuple,
Buffer  buffer,
Snapshot  snapshot 
)

Definition at line 4041 of file predicate.c.

References Assert, SERIALIZABLEXACT::earliestOutConflictCommit, elog, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, FlagRWConflict(), SERIALIZABLEXACT::flags, GetTopTransactionIdIfAny(), HASH_FIND, hash_search(), HEAPTUPLE_DEAD, HEAPTUPLE_DELETE_IN_PROGRESS, HEAPTUPLE_INSERT_IN_PROGRESS, HEAPTUPLE_LIVE, HEAPTUPLE_RECENTLY_DEAD, HeapTupleHeaderGetUpdateXid, HeapTupleHeaderGetXmin, HeapTupleSatisfiesVacuum(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, InvalidTransactionId, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SERIALIZABLEXID::myXact, OldSerXidGetMinConflictCommitSeqNo(), RWConflictExists(), SERIALIZABLEXACT::SeqNo, SerializationNeededForRead(), SHMQueueEmpty(), SubTransGetTopmostTransaction(), SXACT_FLAG_DOOMED, SXACT_FLAG_SUMMARY_CONFLICT_OUT, SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, HeapTupleData::t_data, SERIALIZABLEXACT::topXid, TransactionIdEquals, TransactionIdFollowsOrEquals(), TransactionIdIsValid, TransactionIdPrecedes(), TransactionXmin, SERIALIZABLEXIDTAG::xid, and XidIsConcurrent().

Referenced by heap_fetch(), heap_get_latest_tid(), heap_hot_search_buffer(), heapam_scan_bitmap_next_block(), heapam_scan_sample_next_tuple(), heapgetpage(), and heapgettup().

4044 {
4045  TransactionId xid;
4046  SERIALIZABLEXIDTAG sxidtag;
4047  SERIALIZABLEXID *sxid;
4048  SERIALIZABLEXACT *sxact;
4049  HTSV_Result htsvResult;
4050 
4051  if (!SerializationNeededForRead(relation, snapshot))
4052  return;
4053 
4054  /* Check if someone else has already decided that we need to die */
4056  {
4057  ereport(ERROR,
4058  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4059  errmsg("could not serialize access due to read/write dependencies among transactions"),
4060  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4061  errhint("The transaction might succeed if retried.")));
4062  }
4063 
4064  /*
4065  * Check to see whether the tuple has been written to by a concurrent
4066  * transaction, either to create it not visible to us, or to delete it
4067  * while it is visible to us. The "visible" bool indicates whether the
4068  * tuple is visible to us, while HeapTupleSatisfiesVacuum checks what else
4069  * is going on with it.
4070  */
4071  htsvResult = HeapTupleSatisfiesVacuum(tuple, TransactionXmin, buffer);
4072  switch (htsvResult)
4073  {
4074  case HEAPTUPLE_LIVE:
4075  if (visible)
4076  return;
4077  xid = HeapTupleHeaderGetXmin(tuple->t_data);
4078  break;
4080  if (!visible)
4081  return;
4082  xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
4083  break;
4085  xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
4086  break;
4088  xid = HeapTupleHeaderGetXmin(tuple->t_data);
4089  break;
4090  case HEAPTUPLE_DEAD:
4091  return;
4092  default:
4093 
4094  /*
4095  * The only way to get to this default clause is if a new value is
4096  * added to the enum type without adding it to this switch
4097  * statement. That's a bug, so elog.
4098  */
4099  elog(ERROR, "unrecognized return value from HeapTupleSatisfiesVacuum: %u", htsvResult);
4100 
4101  /*
4102  * In spite of having all enum values covered and calling elog on
4103  * this default, some compilers think this is a code path which
4104  * allows xid to be used below without initialization. Silence
4105  * that warning.
4106  */
4107  xid = InvalidTransactionId;
4108  }
4111 
4112  /*
4113  * Find top level xid. Bail out if xid is too early to be a conflict, or
4114  * if it's our own xid.
4115  */
4117  return;
4118  xid = SubTransGetTopmostTransaction(xid);
4120  return;
4122  return;
4123 
4124  /*
4125  * Find sxact or summarized info for the top level xid.
4126  */
4127  sxidtag.xid = xid;
4128  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4129  sxid = (SERIALIZABLEXID *)
4130  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4131  if (!sxid)
4132  {
4133  /*
4134  * Transaction not found in "normal" SSI structures. Check whether it
4135  * got pushed out to SLRU storage for "old committed" transactions.
4136  */
4137  SerCommitSeqNo conflictCommitSeqNo;
4138 
4139  conflictCommitSeqNo = OldSerXidGetMinConflictCommitSeqNo(xid);
4140  if (conflictCommitSeqNo != 0)
4141  {
4142  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4144  || conflictCommitSeqNo
4146  ereport(ERROR,
4147  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4148  errmsg("could not serialize access due to read/write dependencies among transactions"),
4149  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4150  errhint("The transaction might succeed if retried.")));
4151 
4154  ereport(ERROR,
4155  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4156  errmsg("could not serialize access due to read/write dependencies among transactions"),
4157  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4158  errhint("The transaction might succeed if retried.")));
4159 
4161  }
4162 
4163  /* It's not serializable or otherwise not important. */
4164  LWLockRelease(SerializableXactHashLock);
4165  return;
4166  }
4167  sxact = sxid->myXact;
4168  Assert(TransactionIdEquals(sxact->topXid, xid));
4169  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4170  {
4171  /* Can't conflict with ourself or a transaction that will roll back. */
4172  LWLockRelease(SerializableXactHashLock);
4173  return;
4174  }
4175 
4176  /*
4177  * We have a conflict out to a transaction which has a conflict out to a
4178  * summarized transaction. That summarized transaction must have
4179  * committed first, and we can't tell when it committed in relation to our
4180  * snapshot acquisition, so something needs to be canceled.
4181  */
4182  if (SxactHasSummaryConflictOut(sxact))
4183  {
4184  if (!SxactIsPrepared(sxact))
4185  {
4186  sxact->flags |= SXACT_FLAG_DOOMED;
4187  LWLockRelease(SerializableXactHashLock);
4188  return;
4189  }
4190  else
4191  {
4192  LWLockRelease(SerializableXactHashLock);
4193  ereport(ERROR,
4194  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4195  errmsg("could not serialize access due to read/write dependencies among transactions"),
4196  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4197  errhint("The transaction might succeed if retried.")));
4198  }
4199  }
4200 
4201  /*
4202  * If this is a read-only transaction and the writing transaction has
4203  * committed, and it doesn't have a rw-conflict to a transaction which
4204  * committed before it, no conflict.
4205  */
4207  && SxactIsCommitted(sxact)
4208  && !SxactHasSummaryConflictOut(sxact)
4209  && (!SxactHasConflictOut(sxact)
4211  {
4212  /* Read-only transaction will appear to run first. No conflict. */
4213  LWLockRelease(SerializableXactHashLock);
4214  return;
4215  }
4216 
4217  if (!XidIsConcurrent(xid))
4218  {
4219  /* This write was already in our snapshot; no conflict. */
4220  LWLockRelease(SerializableXactHashLock);
4221  return;
4222  }
4223 
4225  {
4226  /* We don't want duplicate conflict records in the list. */
4227  LWLockRelease(SerializableXactHashLock);
4228  return;
4229  }
4230 
4231  /*
4232  * Flag the conflict. But first, if this conflict creates a dangerous
4233  * structure, ereport an error.
4234  */
4236  LWLockRelease(SerializableXactHashLock);
4237 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:365
#define SxactIsReadOnly(sxact)
Definition: predicate.c:279
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:656
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:4602
uint32 TransactionId
Definition: c.h:508
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:280
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
Definition: subtrans.c:150
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:3998
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
int errcode(int sqlerrcode)
Definition: elog.c:608
static HTAB * SerializableXidHash
Definition: predicate.c:394
SERIALIZABLEXACT * myXact
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
#define SxactIsPrepared(sxact)
Definition: predicate.c:276
int errdetail_internal(const char *fmt,...)
Definition: elog.c:984
TransactionId TransactionXmin
Definition: snapmgr.c:166
HeapTupleHeader t_data
Definition: htup.h:68
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define SxactIsDoomed(sxact)
Definition: predicate.c:278
#define ERROR
Definition: elog.h:43
union SERIALIZABLEXACT::@109 SeqNo
#define InvalidTransactionId
Definition: transam.h:31
SerCommitSeqNo lastCommitBeforeSnapshot
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:409
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
#define ereport(elevel, rest)
Definition: elog.h:141
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:281
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define InvalidSerCommitSeqNo
bool SHMQueueEmpty(const SHM_QUEUE *queue)
Definition: shmqueue.c:180
SerCommitSeqNo earliestOutConflictCommit
static SerCommitSeqNo OldSerXidGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:926
uint64 SerCommitSeqNo
#define SXACT_FLAG_DOOMED
#define SxactHasConflictOut(sxact)
Definition: predicate.c:287
#define Assert(condition)
Definition: c.h:733
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:517
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
HTSV_Result
Definition: heapam.h:86
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define SxactIsCommitted(sxact)
Definition: predicate.c:275

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 1018 of file predicate.c.

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

Referenced by CheckPointGuts().

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

◆ CheckTableForSerializableConflictIn()

void CheckTableForSerializableConflictIn ( Relation  relation)

Definition at line 4510 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().

4511 {
4512  HASH_SEQ_STATUS seqstat;
4513  PREDICATELOCKTARGET *target;
4514  Oid dbId;
4515  Oid heapId;
4516  int i;
4517 
4518  /*
4519  * Bail out quickly if there are no serializable transactions running.
4520  * It's safe to check this without taking locks because the caller is
4521  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4522  * would matter here can be acquired while that is held.
4523  */
4525  return;
4526 
4527  if (!SerializationNeededForWrite(relation))
4528  return;
4529 
4530  /*
4531  * We're doing a write which might cause rw-conflicts now or later.
4532  * Memorize that fact.
4533  */
4534  MyXactDidWrite = true;
4535 
4536  Assert(relation->rd_index == NULL); /* not an index relation */
4537 
4538  dbId = relation->rd_node.dbNode;
4539  heapId = relation->rd_id;
4540 
4541  LWLockAcquire(SerializablePredicateLockListLock, LW_EXCLUSIVE);
4542  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4544  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4545 
4546  /* Scan through target list */
4548 
4549  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4550  {
4551  PREDICATELOCK *predlock;
4552 
4553  /*
4554  * Check whether this is a target which needs attention.
4555  */
4556  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4557  continue; /* wrong relation id */
4558  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4559  continue; /* wrong database id */
4560 
4561  /*
4562  * Loop through locks for this target and flag conflicts.
4563  */
4564  predlock = (PREDICATELOCK *)
4565  SHMQueueNext(&(target->predicateLocks),
4566  &(target->predicateLocks),
4567  offsetof(PREDICATELOCK, targetLink));
4568  while (predlock)
4569  {
4570  PREDICATELOCK *nextpredlock;
4571 
4572  nextpredlock = (PREDICATELOCK *)
4573  SHMQueueNext(&(target->predicateLocks),
4574  &(predlock->targetLink),
4575  offsetof(PREDICATELOCK, targetLink));
4576 
4577  if (predlock->tag.myXact != MySerializableXact
4579  {
4581  }
4582 
4583  predlock = nextpredlock;
4584  }
4585  }
4586 
4587  /* Release locks in reverse order */
4588  LWLockRelease(SerializableXactHashLock);
4589  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4591  LWLockRelease(SerializablePredicateLockListLock);
4592 }
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:656
static HTAB * PredicateLockTargetHash
Definition: predicate.c:395
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4602
static PredXactList PredXact
Definition: predicate.c:382
TransactionId SxactGlobalXmin
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:561
unsigned int Oid
Definition: postgres_ext.h:31
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
Form_pg_index rd_index
Definition: rel.h:143
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
Oid rd_id
Definition: rel.h:85
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:54
#define Assert(condition)
Definition: c.h:733
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:259
int i
SERIALIZABLEXACT * myXact
static bool MyXactDidWrite
Definition: predicate.c:420
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define offsetof(type, field)
Definition: c.h:656
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:121

◆ CheckTargetForConflictsIn()

static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag)
static

Definition at line 4244 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().

4245 {
4246  uint32 targettaghash;
4247  LWLock *partitionLock;
4248  PREDICATELOCKTARGET *target;
4249  PREDICATELOCK *predlock;
4250  PREDICATELOCK *mypredlock = NULL;
4251  PREDICATELOCKTAG mypredlocktag;
4252 
4254 
4255  /*
4256  * The same hash and LW lock apply to the lock target and the lock itself.
4257  */
4258  targettaghash = PredicateLockTargetTagHashCode(targettag);
4259  partitionLock = PredicateLockHashPartitionLock(targettaghash);
4260  LWLockAcquire(partitionLock, LW_SHARED);
4261  target = (PREDICATELOCKTARGET *)
4263  targettag, targettaghash,
4264  HASH_FIND, NULL);
4265  if (!target)
4266  {
4267  /* Nothing has this target locked; we're done here. */
4268  LWLockRelease(partitionLock);
4269  return;
4270  }
4271 
4272  /*
4273  * Each lock for an overlapping transaction represents a conflict: a
4274  * rw-dependency in to this transaction.
4275  */
4276  predlock = (PREDICATELOCK *)
4277  SHMQueueNext(&(target->predicateLocks),
4278  &(target->predicateLocks),
4279  offsetof(PREDICATELOCK, targetLink));
4280  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4281  while (predlock)
4282  {
4283  SHM_QUEUE *predlocktargetlink;
4284  PREDICATELOCK *nextpredlock;
4285  SERIALIZABLEXACT *sxact;
4286 
4287  predlocktargetlink = &(predlock->targetLink);
4288  nextpredlock = (PREDICATELOCK *)
4289  SHMQueueNext(&(target->predicateLocks),
4290  predlocktargetlink,
4291  offsetof(PREDICATELOCK, targetLink));
4292 
4293  sxact = predlock->tag.myXact;
4294  if (sxact == MySerializableXact)
4295  {
4296  /*
4297  * If we're getting a write lock on a tuple, we don't need a
4298  * predicate (SIREAD) lock on the same tuple. We can safely remove
4299  * our SIREAD lock, but we'll defer doing so until after the loop
4300  * because that requires upgrading to an exclusive partition lock.
4301  *
4302  * We can't use this optimization within a subtransaction because
4303  * the subtransaction could roll back, and we would be left
4304  * without any lock at the top level.
4305  */
4306  if (!IsSubTransaction()
4307  && GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
4308  {
4309  mypredlock = predlock;
4310  mypredlocktag = predlock->tag;
4311  }
4312  }
4313  else if (!SxactIsDoomed(sxact)
4314  && (!SxactIsCommitted(sxact)
4316  sxact->finishedBefore))
4318  {
4319  LWLockRelease(SerializableXactHashLock);
4320  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4321 
4322  /*
4323  * Re-check after getting exclusive lock because the other
4324  * transaction may have flagged a conflict.
4325  */
4326  if (!SxactIsDoomed(sxact)
4327  && (!SxactIsCommitted(sxact)
4329  sxact->finishedBefore))
4331  {
4333  }
4334 
4335  LWLockRelease(SerializableXactHashLock);
4336  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4337  }
4338 
4339  predlock = nextpredlock;
4340  }
4341  LWLockRelease(SerializableXactHashLock);
4342  LWLockRelease(partitionLock);
4343 
4344  /*
4345  * If we found one of our own SIREAD locks to remove, remove it now.
4346  *
4347  * At this point our transaction already has a RowExclusiveLock on the
4348  * relation, so we are OK to drop the predicate lock on the tuple, if
4349  * found, without fearing that another write against the tuple will occur
4350  * before the MVCC information makes it to the buffer.
4351  */
4352  if (mypredlock != NULL)
4353  {
4354  uint32 predlockhashcode;
4355  PREDICATELOCK *rmpredlock;
4356 
4357  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
4358  if (IsInParallelMode())
4360  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4361  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4362 
4363  /*
4364  * Remove the predicate lock from shared memory, if it wasn't removed
4365  * while the locks were released. One way that could happen is from
4366  * autovacuum cleaning up an index.
4367  */
4368  predlockhashcode = PredicateLockHashCodeFromTargetHashCode
4369  (&mypredlocktag, targettaghash);
4370  rmpredlock = (PREDICATELOCK *)
4372  &mypredlocktag,
4373  predlockhashcode,
4374  HASH_FIND, NULL);
4375  if (rmpredlock != NULL)
4376  {
4377  Assert(rmpredlock == mypredlock);
4378 
4379  SHMQueueDelete(&(mypredlock->targetLink));
4380  SHMQueueDelete(&(mypredlock->xactLink));
4381 
4382  rmpredlock = (PREDICATELOCK *)
4384  &mypredlocktag,
4385  predlockhashcode,
4386  HASH_REMOVE, NULL);
4387  Assert(rmpredlock == mypredlock);
4388 
4389  RemoveTargetIfNoLongerUsed(target, targettaghash);
4390  }
4391 
4392  LWLockRelease(SerializableXactHashLock);
4393  LWLockRelease(partitionLock);
4394  if (IsInParallelMode())
4396  LWLockRelease(SerializablePredicateLockListLock);
4397 
4398  if (rmpredlock != NULL)
4399  {
4400  /*
4401  * Remove entry in local lock table if it exists. It's OK if it
4402  * doesn't exist; that means the lock was transferred to a new
4403  * target by a different backend.
4404  */
4406  targettag, targettaghash,
4407  HASH_REMOVE, NULL);
4408 
4409  DecrementParentLocks(targettag);
4410  }
4411  }
4412 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
TransactionId finishedBefore
Definition: lwlock.h:32
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:656
static HTAB * PredicateLockTargetHash
Definition: predicate.c:395
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4602
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2099
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:256
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define SxactIsDoomed(sxact)
Definition: predicate.c:278
#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag)
bool IsInParallelMode(void)
Definition: xact.c:996
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:314
static HTAB * PredicateLockHash
Definition: predicate.c:396
#define InvalidSerializableXact
unsigned int uint32
Definition: c.h:359
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2317
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:301
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:733
static HTAB * LocalPredicateLockHash
Definition: predicate.c:412
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
bool IsSubTransaction(void)
Definition: xact.c:4708
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
SERIALIZABLEXACT * myXact
#define SxactIsCommitted(sxact)
Definition: predicate.c:275
#define offsetof(type, field)
Definition: c.h:656

◆ ClearOldPredicateLocks()

static void ClearOldPredicateLocks ( void  )
static

Definition at line 3678 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().

3679 {
3680  SERIALIZABLEXACT *finishedSxact;
3681  PREDICATELOCK *predlock;
3682 
3683  /*
3684  * Loop through finished transactions. They are in commit order, so we can
3685  * stop as soon as we find one that's still interesting.
3686  */
3687  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3688  finishedSxact = (SERIALIZABLEXACT *)
3691  offsetof(SERIALIZABLEXACT, finishedLink));
3692  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3693  while (finishedSxact)
3694  {
3695  SERIALIZABLEXACT *nextSxact;
3696 
3697  nextSxact = (SERIALIZABLEXACT *)
3699  &(finishedSxact->finishedLink),
3700  offsetof(SERIALIZABLEXACT, finishedLink));
3704  {
3705  /*
3706  * This transaction committed before any in-progress transaction
3707  * took its snapshot. It's no longer interesting.
3708  */
3709  LWLockRelease(SerializableXactHashLock);
3710  SHMQueueDelete(&(finishedSxact->finishedLink));
3711  ReleaseOneSerializableXact(finishedSxact, false, false);
3712  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3713  }
3714  else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3715  && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3716  {
3717  /*
3718  * Any active transactions that took their snapshot before this
3719  * transaction committed are read-only, so we can clear part of
3720  * its state.
3721  */
3722  LWLockRelease(SerializableXactHashLock);
3723 
3724  if (SxactIsReadOnly(finishedSxact))
3725  {
3726  /* A read-only transaction can be removed entirely */
3727  SHMQueueDelete(&(finishedSxact->finishedLink));
3728  ReleaseOneSerializableXact(finishedSxact, false, false);
3729  }
3730  else
3731  {
3732  /*
3733  * A read-write transaction can only be partially cleared. We
3734  * need to keep the SERIALIZABLEXACT but can release the
3735  * SIREAD locks and conflicts in.
3736  */
3737  ReleaseOneSerializableXact(finishedSxact, true, false);
3738  }
3739 
3741  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3742  }
3743  else
3744  {
3745  /* Still interesting. */
3746  break;
3747  }
3748  finishedSxact = nextSxact;
3749  }
3750  LWLockRelease(SerializableXactHashLock);
3751 
3752  /*
3753  * Loop through predicate locks on dummy transaction for summarized data.
3754  */
3755  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
3756  predlock = (PREDICATELOCK *)
3759  offsetof(PREDICATELOCK, xactLink));
3760  while (predlock)
3761  {
3762  PREDICATELOCK *nextpredlock;
3763  bool canDoPartialCleanup;
3764 
3765  nextpredlock = (PREDICATELOCK *)
3767  &predlock->xactLink,
3768  offsetof(PREDICATELOCK, xactLink));
3769 
3770  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3771  Assert(predlock->commitSeqNo != 0);
3773  canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
3774  LWLockRelease(SerializableXactHashLock);
3775 
3776  /*
3777  * If this lock originally belonged to an old enough transaction, we
3778  * can release it.
3779  */
3780  if (canDoPartialCleanup)
3781  {
3782  PREDICATELOCKTAG tag;
3783  PREDICATELOCKTARGET *target;
3784  PREDICATELOCKTARGETTAG targettag;
3785  uint32 targettaghash;
3786  LWLock *partitionLock;
3787 
3788  tag = predlock->tag;
3789  target = tag.myTarget;
3790  targettag = target->tag;
3791  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3792  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3793 
3794  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3795 
3796  SHMQueueDelete(&(predlock->targetLink));
3797  SHMQueueDelete(&(predlock->xactLink));
3798 
3801  targettaghash),
3802  HASH_REMOVE, NULL);
3803  RemoveTargetIfNoLongerUsed(target, targettaghash);
3804 
3805  LWLockRelease(partitionLock);
3806  }
3807 
3808  predlock = nextpredlock;
3809  }
3810 
3811  LWLockRelease(SerializablePredicateLockListLock);
3812  LWLockRelease(SerializableFinishedListLock);
3813 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
#define SxactIsReadOnly(sxact)
Definition: predicate.c:279
TransactionId finishedBefore
Definition: lwlock.h:32
static PredXactList PredXact
Definition: predicate.c:382
TransactionId SxactGlobalXmin
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2099
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:256
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:314
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
static HTAB * PredicateLockHash
Definition: predicate.c:396
unsigned int uint32
Definition: c.h:359
#define InvalidSerCommitSeqNo
SerCommitSeqNo commitSeqNo
SerCommitSeqNo HavePartialClearedThrough
PREDICATELOCKTAG tag
SerCommitSeqNo CanPartialClearThrough
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:301
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:3835
#define Assert(condition)
Definition: c.h:733
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:360
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static SHM_QUEUE * FinishedSerializableTransactions
Definition: predicate.c:397
#define offsetof(type, field)
Definition: c.h:656
PREDICATELOCKTARGET * myTarget

◆ CoarserLockCovers()

static bool CoarserLockCovers ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2027 of file predicate.c.

References GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

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

◆ CreateLocalPredicateLockHash()

static void CreateLocalPredicateLockHash ( void  )
static

Definition at line 1855 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().

1856 {
1857  HASHCTL hash_ctl;
1858 
1859  /* Initialize the backend-local hash table of parent locks */
1860  Assert(LocalPredicateLockHash == NULL);
1861  MemSet(&hash_ctl, 0, sizeof(hash_ctl));
1862  hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1863  hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1864  LocalPredicateLockHash = hash_create("Local predicate lock",
1866  &hash_ctl,
1867  HASH_ELEM | HASH_BLOBS);
1868 }
#define HASH_ELEM
Definition: hsearch.h:87
Size entrysize
Definition: hsearch.h:73
#define MemSet(start, val, len)
Definition: c.h:956
int max_predicate_locks_per_xact
Definition: predicate.c:369
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:316
Size keysize
Definition: hsearch.h:72
#define Assert(condition)
Definition: c.h:733
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
static HTAB * LocalPredicateLockHash
Definition: predicate.c:412

◆ CreatePredicateLock()

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

Definition at line 2379 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().

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

◆ CreatePredXact()

static SERIALIZABLEXACT * CreatePredXact ( void  )
static

Definition at line 583 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().

584 {
585  PredXactListElement ptle;
586 
587  ptle = (PredXactListElement)
591  if (!ptle)
592  return NULL;
593 
594  SHMQueueDelete(&ptle->link);
596  return &ptle->sxact;
597 }
static PredXactList PredXact
Definition: predicate.c:382
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:656

◆ DecrementParentLocks()

static void DecrementParentLocks ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2317 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().

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

◆ DeleteChildTargetLocks()

static void DeleteChildTargetLocks ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2130 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().

2131 {
2132  SERIALIZABLEXACT *sxact;
2133  PREDICATELOCK *predlock;
2134 
2135  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
2136  sxact = MySerializableXact;
2137  if (IsInParallelMode())
2139  predlock = (PREDICATELOCK *)
2140  SHMQueueNext(&(sxact->predicateLocks),
2141  &(sxact->predicateLocks),
2142  offsetof(PREDICATELOCK, xactLink));
2143  while (predlock)
2144  {
2145  SHM_QUEUE *predlocksxactlink;
2146  PREDICATELOCK *nextpredlock;
2147  PREDICATELOCKTAG oldlocktag;
2148  PREDICATELOCKTARGET *oldtarget;
2149  PREDICATELOCKTARGETTAG oldtargettag;
2150 
2151  predlocksxactlink = &(predlock->xactLink);
2152  nextpredlock = (PREDICATELOCK *)
2153  SHMQueueNext(&(sxact->predicateLocks),
2154  predlocksxactlink,
2155  offsetof(PREDICATELOCK, xactLink));
2156 
2157  oldlocktag = predlock->tag;
2158  Assert(oldlocktag.myXact == sxact);
2159  oldtarget = oldlocktag.myTarget;
2160  oldtargettag = oldtarget->tag;
2161 
2162  if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
2163  {
2164  uint32 oldtargettaghash;
2165  LWLock *partitionLock;
2167 
2168  oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2169  partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2170 
2171  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2172 
2173  SHMQueueDelete(predlocksxactlink);
2174  SHMQueueDelete(&(predlock->targetLink));
2175  rmpredlock = hash_search_with_hash_value
2177  &oldlocktag,
2179  oldtargettaghash),
2180  HASH_REMOVE, NULL);
2181  Assert(rmpredlock == predlock);
2182 
2183  RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2184 
2185  LWLockRelease(partitionLock);
2186 
2187  DecrementParentLocks(&oldtargettag);
2188  }
2189 
2190  predlock = nextpredlock;
2191  }
2192  if (IsInParallelMode())
2194  LWLockRelease(SerializablePredicateLockListLock);
2195 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
Definition: lwlock.h:32
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2099
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:256
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
bool IsInParallelMode(void)
Definition: xact.c:996
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:314
static HTAB * PredicateLockHash
Definition: predicate.c:396
unsigned int uint32
Definition: c.h:359
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2317
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:301
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:733
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
#define TargetTagIsCoveredBy(covered_target, covering_target)
Definition: predicate.c:231
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
SERIALIZABLEXACT * myXact
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:123
#define offsetof(type, field)
Definition: c.h:656
PREDICATELOCKTARGET * myTarget

◆ DeleteLockTarget()

static void DeleteLockTarget ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

Definition at line 2597 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().

2598 {
2599  PREDICATELOCK *predlock;
2600  SHM_QUEUE *predlocktargetlink;
2601  PREDICATELOCK *nextpredlock;
2602  bool found;
2603 
2604  Assert(LWLockHeldByMeInMode(SerializablePredicateLockListLock,
2605  LW_EXCLUSIVE));
2607 
2608  predlock = (PREDICATELOCK *)
2609  SHMQueueNext(&(target->predicateLocks),
2610  &(target->predicateLocks),
2611  offsetof(PREDICATELOCK, targetLink));
2612  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2613  while (predlock)
2614  {
2615  predlocktargetlink = &(predlock->targetLink);
2616  nextpredlock = (PREDICATELOCK *)
2617  SHMQueueNext(&(target->predicateLocks),
2618  predlocktargetlink,
2619  offsetof(PREDICATELOCK, targetLink));
2620 
2621  SHMQueueDelete(&(predlock->xactLink));
2622  SHMQueueDelete(&(predlock->targetLink));
2623 
2626  &predlock->tag,
2628  targettaghash),
2629  HASH_REMOVE, &found);
2630  Assert(found);
2631 
2632  predlock = nextpredlock;
2633  }
2634  LWLockRelease(SerializableXactHashLock);
2635 
2636  /* Remove the target itself, if possible. */
2637  RemoveTargetIfNoLongerUsed(target, targettaghash);
2638 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
bool LWLockHeldByMeInMode(LWLock *l, LWLockMode mode)
Definition: lwlock.c:1860
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1842
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2099
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:256
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:314
static HTAB * PredicateLockHash
Definition: predicate.c:396
PREDICATELOCKTAG tag
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:733
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
#define offsetof(type, field)
Definition: c.h:656

◆ DropAllPredicateLocksFromTable()

static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
)
static

Definition at line 2885 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().

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

◆ FirstPredXact()

static SERIALIZABLEXACT * FirstPredXact ( void  )
static

Definition at line 615 of file predicate.c.

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

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

616 {
617  PredXactListElement ptle;
618 
619  ptle = (PredXactListElement)
623  if (!ptle)
624  return NULL;
625 
626  return &ptle->sxact;
627 }
static PredXactList PredXact
Definition: predicate.c:382
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:656

◆ FlagRWConflict()

static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4602 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().

4603 {
4604  Assert(reader != writer);
4605 
4606  /* First, see if this conflict causes failure. */
4608 
4609  /* Actually do the conflict flagging. */
4610  if (reader == OldCommittedSxact)
4612  else if (writer == OldCommittedSxact)
4614  else
4615  SetRWConflict(reader, writer);
4616 }
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:689
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4637
#define Assert(condition)
Definition: c.h:733
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:360
#define SXACT_FLAG_SUMMARY_CONFLICT_IN

◆ FlagSxactUnsafe()

static void FlagSxactUnsafe ( SERIALIZABLEXACT sxact)
static

Definition at line 753 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().

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

◆ GetParentPredicateLockTag()

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

Definition at line 1988 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().

1990 {
1991  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
1992  {
1993  case PREDLOCKTAG_RELATION:
1994  /* relation locks have no parent lock */
1995  return false;
1996 
1997  case PREDLOCKTAG_PAGE:
1998  /* parent lock is relation lock */
2002 
2003  return true;
2004 
2005  case PREDLOCKTAG_TUPLE:
2006  /* parent lock is page lock */
2011  return true;
2012  }
2013 
2014  /* not reachable */
2015  Assert(false);
2016  return false;
2017 }
#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:733

◆ GetPredicateLockStatusData()

PredicateLockData* GetPredicateLockStatusData ( void  )

Definition at line 1376 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().

1377 {
1378  PredicateLockData *data;
1379  int i;
1380  int els,
1381  el;
1382  HASH_SEQ_STATUS seqstat;
1383  PREDICATELOCK *predlock;
1384 
1385  data = (PredicateLockData *) palloc(sizeof(PredicateLockData));
1386 
1387  /*
1388  * To ensure consistency, take simultaneous locks on all partition locks
1389  * in ascending order, then SerializableXactHashLock.
1390  */
1391  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
1393  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1394 
1395  /* Get number of locks and allocate appropriately-sized arrays. */
1397  data->nelements = els;
1398  data->locktags = (PREDICATELOCKTARGETTAG *)
1399  palloc(sizeof(PREDICATELOCKTARGETTAG) * els);
1400  data->xacts = (SERIALIZABLEXACT *)
1401  palloc(sizeof(SERIALIZABLEXACT) * els);
1402 
1403 
1404  /* Scan through PredicateLockHash and copy contents */
1405  hash_seq_init(&seqstat, PredicateLockHash);
1406 
1407  el = 0;
1408 
1409  while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
1410  {
1411  data->locktags[el] = predlock->tag.myTarget->tag;
1412  data->xacts[el] = *predlock->tag.myXact;
1413  el++;
1414  }
1415 
1416  Assert(el == els);
1417 
1418  /* Release locks in reverse order */
1419  LWLockRelease(SerializableXactHashLock);
1420  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1422 
1423  return data;
1424 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1335
SERIALIZABLEXACT * xacts
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
static HTAB * PredicateLockHash
Definition: predicate.c:396
PREDICATELOCKTARGETTAG * locktags
PREDICATELOCKTAG tag
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:733
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:259
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 1491 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().

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

◆ GetSafeSnapshotBlockingPids()

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

Definition at line 1561 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().

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

◆ GetSerializableTransactionSnapshot()

Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot)

Definition at line 1613 of file predicate.c.

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

Referenced by GetTransactionSnapshot().

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

1698 {
1699  PGPROC *proc;
1700  VirtualTransactionId vxid;
1701  SERIALIZABLEXACT *sxact,
1702  *othersxact;
1703 
1704  /* We only do this for serializable transactions. Once. */
1706 
1708 
1709  /*
1710  * Since all parts of a serializable transaction must use the same
1711  * snapshot, it is too late to establish one after a parallel operation
1712  * has begun.
1713  */
1714  if (IsInParallelMode())
1715  elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
1716 
1717  proc = MyProc;
1718  Assert(proc != NULL);
1719  GET_VXID_FROM_PGPROC(vxid, *proc);
1720 
1721  /*
1722  * First we get the sxact structure, which may involve looping and access
1723  * to the "finished" list to free a structure for use.
1724  *
1725  * We must hold SerializableXactHashLock when taking/checking the snapshot
1726  * to avoid race conditions, for much the same reasons that
1727  * GetSnapshotData takes the ProcArrayLock. Since we might have to
1728  * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
1729  * this means we have to create the sxact first, which is a bit annoying
1730  * (in particular, an elog(ERROR) in procarray.c would cause us to leak
1731  * the sxact). Consider refactoring to avoid this.
1732  */
1733 #ifdef TEST_OLDSERXID
1735 #endif
1736  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1737  do
1738  {
1739  sxact = CreatePredXact();
1740  /* If null, push out committed sxact to SLRU summary & retry. */
1741  if (!sxact)
1742  {
1743  LWLockRelease(SerializableXactHashLock);
1745  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1746  }
1747  } while (!sxact);
1748 
1749  /* Get the snapshot, or check that it's safe to use */
1750  if (!sourcevxid)
1751  snapshot = GetSnapshotData(snapshot);
1752  else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid))
1753  {
1754  ReleasePredXact(sxact);
1755  LWLockRelease(SerializableXactHashLock);
1756  ereport(ERROR,
1757  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1758  errmsg("could not import the requested snapshot"),
1759  errdetail("The source process with PID %d is not running anymore.",
1760  sourcepid)));
1761  }
1762 
1763  /*
1764  * If there are no serializable transactions which are not read-only, we
1765  * can "opt out" of predicate locking and conflict checking for a
1766  * read-only transaction.
1767  *
1768  * The reason this is safe is that a read-only transaction can only become
1769  * part of a dangerous structure if it overlaps a writable transaction
1770  * which in turn overlaps a writable transaction which committed before
1771  * the read-only transaction started. A new writable transaction can
1772  * overlap this one, but it can't meet the other condition of overlapping
1773  * a transaction which committed before this one started.
1774  */
1776  {
1777  ReleasePredXact(sxact);
1778  LWLockRelease(SerializableXactHashLock);
1779  return snapshot;
1780  }
1781 
1782  /* Maintain serializable global xmin info. */
1784  {
1786  PredXact->SxactGlobalXmin = snapshot->xmin;
1788  OldSerXidSetActiveSerXmin(snapshot->xmin);
1789  }
1790  else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
1791  {
1794  }
1795  else
1796  {
1798  }
1799 
1800  /* Initialize the structure. */
1801  sxact->vxid = vxid;
1805  SHMQueueInit(&(sxact->outConflicts));
1806  SHMQueueInit(&(sxact->inConflicts));
1808  sxact->topXid = GetTopTransactionIdIfAny();
1810  sxact->xmin = snapshot->xmin;
1811  sxact->pid = MyProcPid;
1812  SHMQueueInit(&(sxact->predicateLocks));
1813  SHMQueueElemInit(&(sxact->finishedLink));
1814  sxact->flags = 0;
1815  if (XactReadOnly)
1816  {
1817  sxact->flags |= SXACT_FLAG_READ_ONLY;
1818 
1819  /*
1820  * Register all concurrent r/w transactions as possible conflicts; if
1821  * all of them commit without any outgoing conflicts to earlier
1822  * transactions then this snapshot can be deemed safe (and we can run
1823  * without tracking predicate locks).
1824  */
1825  for (othersxact = FirstPredXact();
1826  othersxact != NULL;
1827  othersxact = NextPredXact(othersxact))
1828  {
1829  if (!SxactIsCommitted(othersxact)
1830  && !SxactIsDoomed(othersxact)
1831  && !SxactIsReadOnly(othersxact))
1832  {
1833  SetPossibleUnsafeConflict(sxact, othersxact);
1834  }
1835  }
1836  }
1837  else
1838  {
1842  }
1843 
1844  MySerializableXact = sxact;
1845  MyXactDidWrite = false; /* haven't written anything yet */
1846 
1847  LWLockRelease(SerializableXactHashLock);
1848 
1850 
1851  return snapshot;
1852 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:279
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
TransactionId finishedBefore
int MyProcPid
Definition: globals.c:40
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:80
#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:382
TransactionId SxactGlobalXmin
int errcode(int sqlerrcode)
Definition: elog.c:608
bool RecoveryInProgress(void)
Definition: xlog.c:7931
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define SxactIsDoomed(sxact)
Definition: predicate.c:278
bool IsInParallelMode(void)
Definition: xact.c:996
SHM_QUEUE possibleUnsafeConflicts
#define ERROR
Definition: elog.h:43
int max_prepared_xacts
Definition: twophase.c:117
union SERIALIZABLEXACT::@109 SeqNo
#define InvalidSerializableXact
static void ReleasePredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:600
int MaxBackends
Definition: globals.c:135
VirtualTransactionId vxid
static SERIALIZABLEXACT * NextPredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:630
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 ereport(elevel, rest)
Definition: elog.h:141
#define InvalidSerCommitSeqNo
static SERIALIZABLEXACT * FirstPredXact(void)
Definition: predicate.c:615
SerCommitSeqNo commitSeqNo
bool XactReadOnly
Definition: xact.c:77
#define Assert(condition)
Definition: c.h:733
static void OldSerXidSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:967
SerCommitSeqNo prepareSeqNo
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:1505
SerCommitSeqNo LastSxactCommitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
void SHMQueueElemInit(SHM_QUEUE *queue)
Definition: shmqueue.c:57
int errmsg(const char *fmt,...)
Definition: elog.c:822
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
Definition: predicate.c:715
#define elog(elevel,...)
Definition: elog.h:228
#define SXACT_FLAG_READ_ONLY
static void SummarizeOldestCommittedSxact(void)
Definition: predicate.c:1434
static bool MyXactDidWrite
Definition: predicate.c:420
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1855
#define TransactionIdIsValid(xid)
Definition: transam.h:41
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition: procarray.c:1796
Definition: proc.h:95
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:583
#define SxactIsCommitted(sxact)
Definition: predicate.c:275

◆ InitPredicateLocks()

void InitPredicateLocks ( void  )

Definition at line 1083 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().

1084 {
1085  HASHCTL info;
1086  long max_table_size;
1087  Size requestSize;
1088  bool found;
1089 
1090 #ifndef EXEC_BACKEND
1092 #endif
1093 
1094  /*
1095  * Compute size of predicate lock target hashtable. Note these
1096  * calculations must agree with PredicateLockShmemSize!
1097  */
1098  max_table_size = NPREDICATELOCKTARGETENTS();
1099 
1100  /*
1101  * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1102  * per-predicate-lock-target information.
1103  */
1104  MemSet(&info, 0, sizeof(info));
1105  info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1106  info.entrysize = sizeof(PREDICATELOCKTARGET);
1108 
1109  PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1110  max_table_size,
1111  max_table_size,
1112  &info,
1113  HASH_ELEM | HASH_BLOBS |
1115 
1116  /*
1117  * Reserve a dummy entry in the hash table; we use it to make sure there's
1118  * always one entry available when we need to split or combine a page,
1119  * because running out of space there could mean aborting a
1120  * non-serializable transaction.
1121  */
1122  if (!IsUnderPostmaster)
1123  {
1125  HASH_ENTER, &found);
1126  Assert(!found);
1127  }
1128 
1129  /* Pre-calculate the hash and partition lock of the scratch entry */
1132 
1133  /*
1134  * Allocate hash table for PREDICATELOCK structs. This stores per
1135  * xact-lock-of-a-target information.
1136  */
1137  MemSet(&info, 0, sizeof(info));
1138  info.keysize = sizeof(PREDICATELOCKTAG);
1139  info.entrysize = sizeof(PREDICATELOCK);
1140  info.hash = predicatelock_hash;
1142 
1143  /* Assume an average of 2 xacts per target */
1144  max_table_size *= 2;
1145 
1146  PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1147  max_table_size,
1148  max_table_size,
1149  &info,
1152 
1153  /*
1154  * Compute size for serializable transaction hashtable. Note these
1155  * calculations must agree with PredicateLockShmemSize!
1156  */
1157  max_table_size = (MaxBackends + max_prepared_xacts);
1158 
1159  /*
1160  * Allocate a list to hold information on transactions participating in
1161  * predicate locking.
1162  *
1163  * Assume an average of 10 predicate locking transactions per backend.
1164  * This allows aggressive cleanup while detail is present before data must
1165  * be summarized for storage in SLRU and the "dummy" transaction.
1166  */
1167  max_table_size *= 10;
1168 
1169  PredXact = ShmemInitStruct("PredXactList",
1171  &found);
1172  Assert(found == IsUnderPostmaster);
1173  if (!found)
1174  {
1175  int i;
1176 
1185  requestSize = mul_size((Size) max_table_size,
1187  PredXact->element = ShmemAlloc(requestSize);
1188  /* Add all elements to available list, clean. */
1189  memset(PredXact->element, 0, requestSize);
1190  for (i = 0; i < max_table_size; i++)
1191  {
1193  LWTRANCHE_SXACT);
1195  &(PredXact->element[i].link));
1196  }
1212  }
1213  /* This never changes, so let's keep a local copy. */
1215 
1216  /*
1217  * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1218  * information for serializable transactions which have accessed data.
1219  */
1220  MemSet(&info, 0, sizeof(info));
1221  info.keysize = sizeof(SERIALIZABLEXIDTAG);
1222  info.entrysize = sizeof(SERIALIZABLEXID);
1223 
1224  SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1225  max_table_size,
1226  max_table_size,
1227  &info,
1228  HASH_ELEM | HASH_BLOBS |
1229  HASH_FIXED_SIZE);
1230 
1231  /*
1232  * Allocate space for tracking rw-conflicts in lists attached to the
1233  * transactions.
1234  *
1235  * Assume an average of 5 conflicts per transaction. Calculations suggest
1236  * that this will prevent resource exhaustion in even the most pessimal
1237  * loads up to max_connections = 200 with all 200 connections pounding the
1238  * database with serializable transactions. Beyond that, there may be
1239  * occasional transactions canceled when trying to flag conflicts. That's
1240  * probably OK.
1241  */
1242  max_table_size *= 5;
1243 
1244  RWConflictPool = ShmemInitStruct("RWConflictPool",
1246  &found);
1247  Assert(found == IsUnderPostmaster);
1248  if (!found)
1249  {
1250  int i;
1251 
1253  requestSize = mul_size((Size) max_table_size,
1255  RWConflictPool->element = ShmemAlloc(requestSize);
1256  /* Add all elements to available list, clean. */
1257  memset(RWConflictPool->element, 0, requestSize);
1258  for (i = 0; i < max_table_size; i++)
1259  {
1261  &(RWConflictPool->element[i].outLink));
1262  }
1263  }
1264 
1265  /*
1266  * Create or attach to the header for the list of finished serializable
1267  * transactions.
1268  */
1270  ShmemInitStruct("FinishedSerializableTransactions",
1271  sizeof(SHM_QUEUE),
1272  &found);
1273  Assert(found == IsUnderPostmaster);
1274  if (!found)
1276 
1277  /*
1278  * Initialize the SLRU storage for old committed serializable
1279  * transactions.
1280  */
1281  OldSerXidInit();
1282 }
TransactionId finishedBefore
#define PredXactListDataSize
struct SERIALIZABLEXID SERIALIZABLEXID
static HTAB * PredicateLockTargetHash
Definition: predicate.c:395
#define HASH_ELEM
Definition: hsearch.h:87
#define NPREDICATELOCKTARGETENTS()
Definition: predicate.c:262
static PredXactList PredXact
Definition: predicate.c:382
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:1350
static HTAB * SerializableXidHash
Definition: predicate.c:394
#define MemSet(start, val, len)
Definition: c.h:956
static void OldSerXidInit(void)
Definition: predicate.c:817
void * ShmemAlloc(Size size)
Definition: shmem.c:157
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:906
#define HASH_PARTITION
Definition: hsearch.h:83
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:256
SHM_QUEUE possibleUnsafeConflicts
static HTAB * PredicateLockHash
Definition: predicate.c:396
int max_prepared_xacts
Definition: twophase.c:117
union SERIALIZABLEXACT::@109 SeqNo
static RWConflictPoolHeader RWConflictPool
Definition: predicate.c:388
struct PREDICATELOCK PREDICATELOCK
long num_partitions
Definition: hsearch.h:67
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
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:678
SerCommitSeqNo commitSeqNo
#define RWConflictPoolHeaderDataSize
SerCommitSeqNo HavePartialClearedThrough
#define HASH_BLOBS
Definition: hsearch.h:88
Size mul_size(Size s1, Size s2)
Definition: shmem.c:492
SerCommitSeqNo CanPartialClearThrough
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:301
Size keysize
Definition: hsearch.h:72
#define Assert(condition)
Definition: c.h:733
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:77
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
SerCommitSeqNo prepareSeqNo
size_t Size
Definition: c.h:467
SerCommitSeqNo LastSxactCommitSeqNo
SERIALIZABLEXACT * OldCommittedSxact
#define HASH_FIXED_SIZE
Definition: hsearch.h:96
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:360
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
int i
static const PREDICATELOCKTARGETTAG ScratchTargetTag
Definition: predicate.c:404
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:317
static SHM_QUEUE * FinishedSerializableTransactions
Definition: predicate.c:397
static uint32 ScratchTargetTagHash
Definition: predicate.c:405
static LWLock * ScratchPartitionLock
Definition: predicate.c:406
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:583
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 2215 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().

2216 {
2217  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2218  {
2219  case PREDLOCKTAG_RELATION:
2224 
2225  case PREDLOCKTAG_PAGE:
2227 
2228  case PREDLOCKTAG_TUPLE:
2229 
2230  /*
2231  * not reachable: nothing is finer-granularity than a tuple, so we
2232  * should never try to promote to it.
2233  */
2234  Assert(false);
2235  return 0;
2236  }
2237 
2238  /* not reachable */
2239  Assert(false);
2240  return 0;
2241 }
int max_predicate_locks_per_xact
Definition: predicate.c:369
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define Assert(condition)
Definition: c.h:733
int max_predicate_locks_per_relation
Definition: predicate.c:370
int max_predicate_locks_per_page
Definition: predicate.c:371

◆ NextPredXact()

static SERIALIZABLEXACT * NextPredXact ( SERIALIZABLEXACT sxact)
static

Definition at line 630 of file predicate.c.

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

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

631 {
632  PredXactListElement ptle;
633 
634  Assert(ShmemAddrIsValid(sxact));
635 
636  ptle = (PredXactListElement)
637  (((char *) sxact)
640  ptle = (PredXactListElement)
642  &ptle->link,
644  if (!ptle)
645  return NULL;
646 
647  return &ptle->sxact;
648 }
static PredXactList PredXact
Definition: predicate.c:382
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
bool ShmemAddrIsValid(const void *addr)
Definition: shmem.c:263
#define Assert(condition)
Definition: c.h:733
struct PredXactListElementData * PredXactListElement
#define offsetof(type, field)
Definition: c.h:656

◆ OldSerXidAdd()

static void OldSerXidAdd ( TransactionId  xid,
SerCommitSeqNo  minConflictCommitSeqNo 
)
static

Definition at line 855 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().

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

◆ OldSerXidGetMinConflictCommitSeqNo()

static SerCommitSeqNo OldSerXidGetMinConflictCommitSeqNo ( TransactionId  xid)
static

Definition at line 926 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().

927 {
928  TransactionId headXid;
929  TransactionId tailXid;
931  int slotno;
932 
934 
935  LWLockAcquire(OldSerXidLock, LW_SHARED);
936  headXid = oldSerXidControl->headXid;
937  tailXid = oldSerXidControl->tailXid;
938  LWLockRelease(OldSerXidLock);
939 
940  if (!TransactionIdIsValid(headXid))
941  return 0;
942 
943  Assert(TransactionIdIsValid(tailXid));
944 
945  if (TransactionIdPrecedes(xid, tailXid)
946  || TransactionIdFollows(xid, headXid))
947  return 0;
948 
949  /*
950  * The following function must be called without holding OldSerXidLock,
951  * but will return with that lock held, which must then be released.
952  */
954  OldSerXidPage(xid), xid);
955  val = OldSerXidValue(slotno, xid);
956  LWLockRelease(OldSerXidLock);
957  return val;
958 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:508
#define OldSerXidPage(xid)
Definition: predicate.c:341
#define OldSerXidSlruCtl
Definition: predicate.c:324
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
TransactionId headXid
Definition: predicate.c:346
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:466
uint64 SerCommitSeqNo
#define Assert(condition)
Definition: c.h:733
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
static OldSerXidControl oldSerXidControl
Definition: predicate.c:352
#define OldSerXidValue(slotno, xid)
Definition: predicate.c:337
#define TransactionIdIsValid(xid)
Definition: transam.h:41
long val
Definition: informix.c:684
TransactionId tailXid
Definition: predicate.c:347

◆ OldSerXidInit()

static void OldSerXidInit ( void  )
static

Definition at line 817 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().

818 {
819  bool found;
820 
821  /*
822  * Set up SLRU management of the pg_serial data.
823  */
825  SimpleLruInit(OldSerXidSlruCtl, "oldserxid",
826  NUM_OLDSERXID_BUFFERS, 0, OldSerXidLock, "pg_serial",
828  /* Override default assumption that writes should be fsync'd */
829  OldSerXidSlruCtl->do_fsync = false;
830 
831  /*
832  * Create or attach to the OldSerXidControl structure.
833  */
835  ShmemInitStruct("OldSerXidControlData", sizeof(OldSerXidControlData), &found);
836 
837  Assert(found == IsUnderPostmaster);
838  if (!found)
839  {
840  /*
841  * Set control information to reflect empty SLRU.
842  */
846  }
847 }
struct OldSerXidControlData * OldSerXidControl
Definition: predicate.c:350
#define NUM_OLDSERXID_BUFFERS
Definition: predicate.h:31
#define OldSerXidSlruCtl
Definition: predicate.c:324
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
bool IsUnderPostmaster
Definition: globals.c:109
#define InvalidTransactionId
Definition: transam.h:31
TransactionId headXid
Definition: predicate.c:346
#define Assert(condition)
Definition: c.h:733
static bool OldSerXidPagePrecedesLogically(int p, int q)
Definition: predicate.c:794
static OldSerXidControl oldSerXidControl
Definition: predicate.c:352
TransactionId tailXid
Definition: predicate.c:347
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 794 of file predicate.c.

References Assert, and OLDSERXID_MAX_PAGE.

Referenced by OldSerXidAdd(), and OldSerXidInit().

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

◆ OldSerXidSetActiveSerXmin()

static void OldSerXidSetActiveSerXmin ( TransactionId  xid)
static

Definition at line 967 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().

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

◆ OnConflict_CheckForSerializationFailure()

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

Definition at line 4637 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().

4639 {
4640  bool failure;
4641  RWConflict conflict;
4642 
4643  Assert(LWLockHeldByMe(SerializableXactHashLock));
4644 
4645  failure = false;
4646 
4647  /*------------------------------------------------------------------------
4648  * Check for already-committed writer with rw-conflict out flagged
4649  * (conflict-flag on W means that T2 committed before W):
4650  *
4651  * R ------> W ------> T2
4652  * rw rw
4653  *
4654  * That is a dangerous structure, so we must abort. (Since the writer
4655  * has already committed, we must be the reader)
4656  *------------------------------------------------------------------------
4657  */
4658  if (SxactIsCommitted(writer)
4659  && (SxactHasConflictOut(writer) || SxactHasSummaryConflictOut(writer)))
4660  failure = true;
4661 
4662  /*------------------------------------------------------------------------
4663  * Check whether the writer has become a pivot with an out-conflict
4664  * committed transaction (T2), and T2 committed first:
4665  *
4666  * R ------> W ------> T2
4667  * rw rw
4668  *
4669  * Because T2 must've committed first, there is no anomaly if:
4670  * - the reader committed before T2
4671  * - the writer committed before T2
4672  * - the reader is a READ ONLY transaction and the reader was concurrent
4673  * with T2 (= reader acquired its snapshot before T2 committed)
4674  *
4675  * We also handle the case that T2 is prepared but not yet committed
4676  * here. In that case T2 has already checked for conflicts, so if it
4677  * commits first, making the above conflict real, it's too late for it
4678  * to abort.
4679  *------------------------------------------------------------------------
4680  */
4681  if (!failure)
4682  {
4683  if (SxactHasSummaryConflictOut(writer))
4684  {
4685  failure = true;
4686  conflict = NULL;
4687  }
4688  else
4689  conflict = (RWConflict)
4690  SHMQueueNext(&writer->outConflicts,
4691  &writer->outConflicts,
4692  offsetof(RWConflictData, outLink));
4693  while (conflict)
4694  {
4695  SERIALIZABLEXACT *t2 = conflict->sxactIn;
4696 
4697  if (SxactIsPrepared(t2)
4698  && (!SxactIsCommitted(reader)
4699  || t2->prepareSeqNo <= reader->commitSeqNo)
4700  && (!SxactIsCommitted(writer)
4701  || t2->prepareSeqNo <= writer->commitSeqNo)
4702  && (!SxactIsReadOnly(reader)
4703  || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
4704  {
4705  failure = true;
4706  break;
4707  }
4708  conflict = (RWConflict)
4709  SHMQueueNext(&writer->outConflicts,
4710  &conflict->outLink,
4711  offsetof(RWConflictData, outLink));
4712  }
4713  }
4714 
4715  /*------------------------------------------------------------------------
4716  * Check whether the reader has become a pivot with a writer
4717  * that's committed (or prepared):
4718  *
4719  * T0 ------> R ------> W
4720  * rw rw
4721  *
4722  * Because W must've committed first for an anomaly to occur, there is no
4723  * anomaly if:
4724  * - T0 committed before the writer
4725  * - T0 is READ ONLY, and overlaps the writer
4726  *------------------------------------------------------------------------
4727  */
4728  if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
4729  {
4730  if (SxactHasSummaryConflictIn(reader))
4731  {
4732  failure = true;
4733  conflict = NULL;
4734  }
4735  else
4736  conflict = (RWConflict)
4737  SHMQueueNext(&reader->inConflicts,
4738  &reader->inConflicts,
4739  offsetof(RWConflictData, inLink));
4740  while (conflict)
4741  {
4742  SERIALIZABLEXACT *t0 = conflict->sxactOut;
4743 
4744  if (!SxactIsDoomed(t0)
4745  && (!SxactIsCommitted(t0)
4746  || t0->commitSeqNo >= writer->prepareSeqNo)
4747  && (!SxactIsReadOnly(t0)
4748  || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
4749  {
4750  failure = true;
4751  break;
4752  }
4753  conflict = (RWConflict)
4754  SHMQueueNext(&reader->inConflicts,
4755  &conflict->inLink,
4756  offsetof(RWConflictData, inLink));
4757  }
4758  }
4759 
4760  if (failure)
4761  {
4762  /*
4763  * We have to kill a transaction to avoid a possible anomaly from
4764  * occurring. If the writer is us, we can just ereport() to cause a
4765  * transaction abort. Otherwise we flag the writer for termination,
4766  * causing it to abort when it tries to commit. However, if the writer
4767  * is a prepared transaction, already prepared, we can't abort it
4768  * anymore, so we have to kill the reader instead.
4769  */
4770  if (MySerializableXact == writer)
4771  {
4772  LWLockRelease(SerializableXactHashLock);
4773  ereport(ERROR,
4774  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4775  errmsg("could not serialize access due to read/write dependencies among transactions"),
4776  errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
4777  errhint("The transaction might succeed if retried.")));
4778  }
4779  else if (SxactIsPrepared(writer))
4780  {
4781  LWLockRelease(SerializableXactHashLock);
4782 
4783  /* if we're not the writer, we have to be the reader */
4784  Assert(MySerializableXact == reader);
4785  ereport(ERROR,
4786  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4787  errmsg("could not serialize access due to read/write dependencies among transactions"),
4788  errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
4789  errhint("The transaction might succeed if retried.")));
4790  }
4791  writer->flags |= SXACT_FLAG_DOOMED;
4792  }
4793 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:279
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
int errhint(const char *fmt,...)
Definition: elog.c:1071
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:280
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1842
struct RWConflictData * RWConflict
int errcode(int sqlerrcode)
Definition: elog.c:608
#define SxactIsPrepared(sxact)
Definition: predicate.c:276
int errdetail_internal(const char *fmt,...)
Definition: elog.c:984
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
SERIALIZABLEXACT * sxactIn
#define SxactIsDoomed(sxact)
Definition: predicate.c:278
#define ERROR
Definition: elog.h:43
union SERIALIZABLEXACT::@109 SeqNo
SerCommitSeqNo lastCommitBeforeSnapshot
#define ereport(elevel, rest)
Definition: elog.h:141
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:281
SerCommitSeqNo commitSeqNo
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define SXACT_FLAG_DOOMED
#define SxactHasConflictOut(sxact)
Definition: predicate.c:287
#define Assert(condition)
Definition: c.h:733
SerCommitSeqNo prepareSeqNo
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define SxactIsCommitted(sxact)
Definition: predicate.c:275
#define offsetof(type, field)
Definition: c.h:656
SERIALIZABLEXACT * sxactOut

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

Definition at line 1924 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.

1925 {
1926  PREDICATELOCKTARGETTAG targettag;
1927  uint32 targettaghash;
1928  LWLock *partitionLock;
1929  PREDICATELOCKTARGET *target;
1930 
1932  relation->rd_node.dbNode,
1933  relation->rd_id,
1934  blkno);
1935 
1936  targettaghash = PredicateLockTargetTagHashCode(&targettag);
1937  partitionLock = PredicateLockHashPartitionLock(targettaghash);
1938  LWLockAcquire(partitionLock, LW_SHARED);
1939  target = (PREDICATELOCKTARGET *)
1941  &targettag, targettaghash,
1942  HASH_FIND, NULL);
1943  LWLockRelease(partitionLock);
1944 
1945  return (target != NULL);
1946 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
Definition: lwlock.h:32
static HTAB * PredicateLockTargetHash
Definition: predicate.c:395
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:256
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
unsigned int uint32
Definition: c.h:359
Oid rd_id
Definition: rel.h:85
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:301
RelFileNode rd_node
Definition: rel.h:54
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122

◆ PostPrepare_PredicateLocks()

void PostPrepare_PredicateLocks ( TransactionId  xid)

Definition at line 4982 of file predicate.c.

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

Referenced by PrepareTransaction().

4983 {
4985  return;
4986 
4988 
4989  MySerializableXact->pid = 0;
4990 
4992  LocalPredicateLockHash = NULL;
4993 
4995  MyXactDidWrite = false;
4996 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:814
#define SxactIsPrepared(sxact)
Definition: predicate.c:276
#define InvalidSerializableXact
#define Assert(condition)
Definition: c.h:733
static HTAB * LocalPredicateLockHash
Definition: predicate.c:412
static bool MyXactDidWrite
Definition: predicate.c:420

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4812 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().

4813 {
4814  RWConflict nearConflict;
4815 
4817  return;
4818 
4820 
4821  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4822 
4823  /* Check if someone else has already decided that we need to die */
4825  {
4827  LWLockRelease(SerializableXactHashLock);
4828  ereport(ERROR,
4829  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4830  errmsg("could not serialize access due to read/write dependencies among transactions"),
4831  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4832  errhint("The transaction might succeed if retried.")));
4833  }
4834 
4835  nearConflict = (RWConflict)
4838  offsetof(RWConflictData, inLink));
4839  while (nearConflict)
4840  {
4841  if (!SxactIsCommitted(nearConflict->sxactOut)
4842  && !SxactIsDoomed(nearConflict->sxactOut))
4843  {
4844  RWConflict farConflict;
4845 
4846  farConflict = (RWConflict)
4847  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4848  &nearConflict->sxactOut->inConflicts,
4849  offsetof(RWConflictData, inLink));
4850  while (farConflict)
4851  {
4852  if (farConflict->sxactOut == MySerializableXact
4853  || (!SxactIsCommitted(farConflict->sxactOut)
4854  && !SxactIsReadOnly(farConflict->sxactOut)
4855  && !SxactIsDoomed(farConflict->sxactOut)))
4856  {
4857  /*
4858  * Normally, we kill the pivot transaction to make sure we
4859  * make progress if the failing transaction is retried.
4860  * However, we can't kill it if it's already prepared, so
4861  * in that case we commit suicide instead.
4862  */
4863  if (SxactIsPrepared(nearConflict->sxactOut))
4864  {
4865  LWLockRelease(SerializableXactHashLock);
4866  ereport(ERROR,
4867  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4868  errmsg("could not serialize access due to read/write dependencies among transactions"),
4869  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4870  errhint("The transaction might succeed if retried.")));
4871  }
4872  nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4873  break;
4874  }
4875  farConflict = (RWConflict)
4876  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4877  &farConflict->inLink,
4878  offsetof(RWConflictData, inLink));
4879  }
4880  }
4881 
4882  nearConflict = (RWConflict)
4884  &nearConflict->inLink,
4885  offsetof(RWConflictData, inLink));
4886  }
4887 
4890 
4891  LWLockRelease(SerializableXactHashLock);
4892 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:279
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
int errhint(const char *fmt,...)
Definition: elog.c:1071
static PredXactList PredXact
Definition: predicate.c:382
struct RWConflictData * RWConflict
int errcode(int sqlerrcode)
Definition: elog.c:608
#define SxactIsPrepared(sxact)
Definition: predicate.c:276
int errdetail_internal(const char *fmt,...)
Definition: elog.c:984
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define SxactIsDoomed(sxact)
Definition: predicate.c:278
#define ERROR
Definition: elog.h:43
#define InvalidSerializableXact
#define SXACT_FLAG_PREPARED
#define ereport(elevel, rest)
Definition: elog.h:141
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define SXACT_FLAG_DOOMED
#define Assert(condition)
Definition: c.h:733
SerCommitSeqNo prepareSeqNo
SerCommitSeqNo LastSxactCommitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
#define SxactIsPartiallyReleased(sxact)
Definition: predicate.c:291
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define IsolationIsSerializable()
Definition: xact.h:52
#define SxactIsCommitted(sxact)
Definition: predicate.c:275
#define offsetof(type, field)
Definition: c.h:656
SERIALIZABLEXACT * sxactOut

◆ predicatelock_hash()

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

Definition at line 1350 of file predicate.c.

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

Referenced by InitPredicateLocks().

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

◆ predicatelock_twophase_recover()

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

Definition at line 5031 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.

5033 {
5034  TwoPhasePredicateRecord *record;
5035 
5036  Assert(len == sizeof(TwoPhasePredicateRecord));
5037 
5038  record = (TwoPhasePredicateRecord *) recdata;
5039 
5040  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
5041  (record->type == TWOPHASEPREDICATERECORD_LOCK));
5042 
5043  if (record->type == TWOPHASEPREDICATERECORD_XACT)
5044  {
5045  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
5046  TwoPhasePredicateXactRecord *xactRecord;
5047  SERIALIZABLEXACT *sxact;
5048  SERIALIZABLEXID *sxid;
5049  SERIALIZABLEXIDTAG sxidtag;
5050  bool found;
5051 
5052  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
5053 
5054  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
5055  sxact = CreatePredXact();
5056  if (!sxact)
5057  ereport(ERROR,
5058  (errcode(ERRCODE_OUT_OF_MEMORY),
5059  errmsg("out of shared memory")));
5060 
5061  /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
5062  sxact->vxid.backendId = InvalidBackendId;
5064  sxact->pid = 0;
5065 
5066  /* a prepared xact hasn't committed yet */
5070 
5072 
5073  /*
5074  * Don't need to track this; no transactions running at the time the
5075  * recovered xact started are still active, except possibly other
5076  * prepared xacts and we don't care whether those are RO_SAFE or not.
5077  */
5079 
5080  SHMQueueInit(&(sxact->predicateLocks));
5081  SHMQueueElemInit(&(sxact->finishedLink));
5082 
5083  sxact->topXid = xid;
5084  sxact->xmin = xactRecord->xmin;
5085  sxact->flags = xactRecord->flags;
5086  Assert(SxactIsPrepared(sxact));
5087  if (!SxactIsReadOnly(sxact))
5088  {
5092  }
5093 
5094  /*
5095  * We don't know whether the transaction had any conflicts or not, so
5096  * we'll conservatively assume that it had both a conflict in and a
5097  * conflict out, and represent that with the summary conflict flags.
5098  */
5099  SHMQueueInit(&(sxact->outConflicts));
5100  SHMQueueInit(&(sxact->inConflicts));
5103 
5104  /* Register the transaction's xid */
5105  sxidtag.xid = xid;
5107  &sxidtag,
5108  HASH_ENTER, &found);
5109  Assert(sxid != NULL);
5110  Assert(!found);
5111  sxid->myXact = (SERIALIZABLEXACT *) sxact;
5112 
5113  /*
5114  * Update global xmin. Note that this is a special case compared to
5115  * registering a normal transaction, because the global xmin might go
5116  * backwards. That's OK, because until recovery is over we're not
5117  * going to complete any transactions or create any non-prepared
5118  * transactions, so there's no danger of throwing away.
5119  */
5122  {
5123  PredXact->SxactGlobalXmin = sxact->xmin;
5126  }
5127  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
5128  {
5131  }
5132 
5133  LWLockRelease(SerializableXactHashLock);
5134  }
5135  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
5136  {
5137  /* Lock record. Recreate the PREDICATELOCK */
5138  TwoPhasePredicateLockRecord *lockRecord;
5139  SERIALIZABLEXID *sxid;
5140  SERIALIZABLEXACT *sxact;
5141  SERIALIZABLEXIDTAG sxidtag;
5142  uint32 targettaghash;
5143 
5144  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
5145  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
5146 
5147  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
5148  sxidtag.xid = xid;
5149  sxid = (SERIALIZABLEXID *)
5150  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
5151  LWLockRelease(SerializableXactHashLock);
5152 
5153  Assert(sxid != NULL);
5154  sxact = sxid->myXact;
5155  Assert(sxact != InvalidSerializableXact);
5156 
5157  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5158  }
5159 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:279
TransactionId finishedBefore
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2379
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
static PredXactList PredX