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:358
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 4922 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().

4923 {
4924  PREDICATELOCK *predlock;
4925  SERIALIZABLEXACT *sxact;
4926  TwoPhasePredicateRecord record;
4927  TwoPhasePredicateXactRecord *xactRecord;
4928  TwoPhasePredicateLockRecord *lockRecord;
4929 
4930  sxact = MySerializableXact;
4931  xactRecord = &(record.data.xactRecord);
4932  lockRecord = &(record.data.lockRecord);
4933 
4935  return;
4936 
4937  /* Generate an xact record for our SERIALIZABLEXACT */
4939  xactRecord->xmin = MySerializableXact->xmin;
4940  xactRecord->flags = MySerializableXact->flags;
4941 
4942  /*
4943  * Note that we don't include the list of conflicts in our out in the
4944  * statefile, because new conflicts can be added even after the
4945  * transaction prepares. We'll just make a conservative assumption during
4946  * recovery instead.
4947  */
4948 
4950  &record, sizeof(record));
4951 
4952  /*
4953  * Generate a lock record for each lock.
4954  *
4955  * To do this, we need to walk the predicate lock list in our sxact rather
4956  * than using the local predicate lock table because the latter is not
4957  * guaranteed to be accurate.
4958  */
4959  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
4960 
4961  /*
4962  * No need to take sxact->predicateLockListLock in parallel mode because
4963  * there cannot be any parallel workers running while we are preparing a
4964  * transaction.
4965  */
4967 
4968  predlock = (PREDICATELOCK *)
4969  SHMQueueNext(&(sxact->predicateLocks),
4970  &(sxact->predicateLocks),
4971  offsetof(PREDICATELOCK, xactLink));
4972 
4973  while (predlock != NULL)
4974  {
4976  lockRecord->target = predlock->tag.myTarget->tag;
4977 
4979  &record, sizeof(record));
4980 
4981  predlock = (PREDICATELOCK *)
4982  SHMQueueNext(&(sxact->predicateLocks),
4983  &(predlock->xactLink),
4984  offsetof(PREDICATELOCK, xactLink));
4985  }
4986 
4987  LWLockRelease(SerializablePredicateLockListLock);
4988 }
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:1204
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:945
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:732
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
TwoPhasePredicateLockRecord lockRecord
#define offsetof(type, field)
Definition: c.h:655
PREDICATELOCKTARGET * myTarget

◆ AttachSerializableXact()

void AttachSerializableXact ( SerializableXactHandle  handle)

Definition at line 5192 of file predicate.c.

References Assert, CreateLocalPredicateLockHash(), and InvalidSerializableXact.

Referenced by ParallelWorkerMain().

5193 {
5194 
5196 
5197  MySerializableXact = (SERIALIZABLEXACT *) handle;
5200 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
#define InvalidSerializableXact
#define Assert(condition)
Definition: c.h:732
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 4442 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().

4444 {
4445  PREDICATELOCKTARGETTAG targettag;
4446 
4447  if (!SerializationNeededForWrite(relation))
4448  return;
4449 
4450  /* Check if someone else has already decided that we need to die */
4452  ereport(ERROR,
4453  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4454  errmsg("could not serialize access due to read/write dependencies among transactions"),
4455  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4456  errhint("The transaction might succeed if retried.")));
4457 
4458  /*
4459  * We're doing a write which might cause rw-conflicts now or later.
4460  * Memorize that fact.
4461  */
4462  MyXactDidWrite = true;
4463 
4464  /*
4465  * It is important that we check for locks from the finest granularity to
4466  * the coarsest granularity, so that granularity promotion doesn't cause
4467  * us to miss a lock. The new (coarser) lock will be acquired before the
4468  * old (finer) locks are released.
4469  *
4470  * It is not possible to take and hold a lock across the checks for all
4471  * granularities because each target could be in a separate partition.
4472  */
4473  if (tuple != NULL)
4474  {
4476  relation->rd_node.dbNode,
4477  relation->rd_id,
4478  ItemPointerGetBlockNumber(&(tuple->t_self)),
4479  ItemPointerGetOffsetNumber(&(tuple->t_self)));
4480  CheckTargetForConflictsIn(&targettag);
4481  }
4482 
4483  if (BufferIsValid(buffer))
4484  {
4486  relation->rd_node.dbNode,
4487  relation->rd_id,
4488  BufferGetBlockNumber(buffer));
4489  CheckTargetForConflictsIn(&targettag);
4490  }
4491 
4493  relation->rd_node.dbNode,
4494  relation->rd_id);
4495  CheckTargetForConflictsIn(&targettag);
4496 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
int errhint(const char *fmt,...)
Definition: elog.c:974
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4260
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
int errcode(int sqlerrcode)
Definition: elog.c:570
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:887
#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:784
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 4057 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().

4060 {
4061  TransactionId xid;
4062  SERIALIZABLEXIDTAG sxidtag;
4063  SERIALIZABLEXID *sxid;
4064  SERIALIZABLEXACT *sxact;
4065  HTSV_Result htsvResult;
4066 
4067  if (!SerializationNeededForRead(relation, snapshot))
4068  return;
4069 
4070  /* Check if someone else has already decided that we need to die */
4072  {
4073  ereport(ERROR,
4074  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4075  errmsg("could not serialize access due to read/write dependencies among transactions"),
4076  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4077  errhint("The transaction might succeed if retried.")));
4078  }
4079 
4080  /*
4081  * Check to see whether the tuple has been written to by a concurrent
4082  * transaction, either to create it not visible to us, or to delete it
4083  * while it is visible to us. The "visible" bool indicates whether the
4084  * tuple is visible to us, while HeapTupleSatisfiesVacuum checks what else
4085  * is going on with it.
4086  */
4087  htsvResult = HeapTupleSatisfiesVacuum(tuple, TransactionXmin, buffer);
4088  switch (htsvResult)
4089  {
4090  case HEAPTUPLE_LIVE:
4091  if (visible)
4092  return;
4093  xid = HeapTupleHeaderGetXmin(tuple->t_data);
4094  break;
4096  if (!visible)
4097  return;
4098  xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
4099  break;
4101  xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
4102  break;
4104  xid = HeapTupleHeaderGetXmin(tuple->t_data);
4105  break;
4106  case HEAPTUPLE_DEAD:
4107  return;
4108  default:
4109 
4110  /*
4111  * The only way to get to this default clause is if a new value is
4112  * added to the enum type without adding it to this switch
4113  * statement. That's a bug, so elog.
4114  */
4115  elog(ERROR, "unrecognized return value from HeapTupleSatisfiesVacuum: %u", htsvResult);
4116 
4117  /*
4118  * In spite of having all enum values covered and calling elog on
4119  * this default, some compilers think this is a code path which
4120  * allows xid to be used below without initialization. Silence
4121  * that warning.
4122  */
4123  xid = InvalidTransactionId;
4124  }
4127 
4128  /*
4129  * Find top level xid. Bail out if xid is too early to be a conflict, or
4130  * if it's our own xid.
4131  */
4133  return;
4134  xid = SubTransGetTopmostTransaction(xid);
4136  return;
4138  return;
4139 
4140  /*
4141  * Find sxact or summarized info for the top level xid.
4142  */
4143  sxidtag.xid = xid;
4144  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4145  sxid = (SERIALIZABLEXID *)
4146  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4147  if (!sxid)
4148  {
4149  /*
4150  * Transaction not found in "normal" SSI structures. Check whether it
4151  * got pushed out to SLRU storage for "old committed" transactions.
4152  */
4153  SerCommitSeqNo conflictCommitSeqNo;
4154 
4155  conflictCommitSeqNo = OldSerXidGetMinConflictCommitSeqNo(xid);
4156  if (conflictCommitSeqNo != 0)
4157  {
4158  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4160  || conflictCommitSeqNo
4162  ereport(ERROR,
4163  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4164  errmsg("could not serialize access due to read/write dependencies among transactions"),
4165  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4166  errhint("The transaction might succeed if retried.")));
4167 
4170  ereport(ERROR,
4171  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4172  errmsg("could not serialize access due to read/write dependencies among transactions"),
4173  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4174  errhint("The transaction might succeed if retried.")));
4175 
4177  }
4178 
4179  /* It's not serializable or otherwise not important. */
4180  LWLockRelease(SerializableXactHashLock);
4181  return;
4182  }
4183  sxact = sxid->myXact;
4184  Assert(TransactionIdEquals(sxact->topXid, xid));
4185  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4186  {
4187  /* Can't conflict with ourself or a transaction that will roll back. */
4188  LWLockRelease(SerializableXactHashLock);
4189  return;
4190  }
4191 
4192  /*
4193  * We have a conflict out to a transaction which has a conflict out to a
4194  * summarized transaction. That summarized transaction must have
4195  * committed first, and we can't tell when it committed in relation to our
4196  * snapshot acquisition, so something needs to be canceled.
4197  */
4198  if (SxactHasSummaryConflictOut(sxact))
4199  {
4200  if (!SxactIsPrepared(sxact))
4201  {
4202  sxact->flags |= SXACT_FLAG_DOOMED;
4203  LWLockRelease(SerializableXactHashLock);
4204  return;
4205  }
4206  else
4207  {
4208  LWLockRelease(SerializableXactHashLock);
4209  ereport(ERROR,
4210  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4211  errmsg("could not serialize access due to read/write dependencies among transactions"),
4212  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4213  errhint("The transaction might succeed if retried.")));
4214  }
4215  }
4216 
4217  /*
4218  * If this is a read-only transaction and the writing transaction has
4219  * committed, and it doesn't have a rw-conflict to a transaction which
4220  * committed before it, no conflict.
4221  */
4223  && SxactIsCommitted(sxact)
4224  && !SxactHasSummaryConflictOut(sxact)
4225  && (!SxactHasConflictOut(sxact)
4227  {
4228  /* Read-only transaction will appear to run first. No conflict. */
4229  LWLockRelease(SerializableXactHashLock);
4230  return;
4231  }
4232 
4233  if (!XidIsConcurrent(xid))
4234  {
4235  /* This write was already in our snapshot; no conflict. */
4236  LWLockRelease(SerializableXactHashLock);
4237  return;
4238  }
4239 
4241  {
4242  /* We don't want duplicate conflict records in the list. */
4243  LWLockRelease(SerializableXactHashLock);
4244  return;
4245  }
4246 
4247  /*
4248  * Flag the conflict. But first, if this conflict creates a dangerous
4249  * structure, ereport an error.
4250  */
4252  LWLockRelease(SerializableXactHashLock);
4253 }
#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:974
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4618
uint32 TransactionId
Definition: c.h:507
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:280
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
Definition: subtrans.c:150
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:4014
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
int errcode(int sqlerrcode)
Definition: elog.c:570
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:887
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:410
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:732
#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:784
#define elog(elevel,...)
Definition: elog.h:226
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:1185
#define OldSerXidPage(xid)
Definition: predicate.c:341
#define OldSerXidSlruCtl
Definition: predicate.c:324
void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1120
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 4526 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().

4527 {
4528  HASH_SEQ_STATUS seqstat;
4529  PREDICATELOCKTARGET *target;
4530  Oid dbId;
4531  Oid heapId;
4532  int i;
4533 
4534  /*
4535  * Bail out quickly if there are no serializable transactions running.
4536  * It's safe to check this without taking locks because the caller is
4537  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4538  * would matter here can be acquired while that is held.
4539  */
4541  return;
4542 
4543  if (!SerializationNeededForWrite(relation))
4544  return;
4545 
4546  /*
4547  * We're doing a write which might cause rw-conflicts now or later.
4548  * Memorize that fact.
4549  */
4550  MyXactDidWrite = true;
4551 
4552  Assert(relation->rd_index == NULL); /* not an index relation */
4553 
4554  dbId = relation->rd_node.dbNode;
4555  heapId = relation->rd_id;
4556 
4557  LWLockAcquire(SerializablePredicateLockListLock, LW_EXCLUSIVE);
4558  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4560  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4561 
4562  /* Scan through target list */
4564 
4565  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4566  {
4567  PREDICATELOCK *predlock;
4568 
4569  /*
4570  * Check whether this is a target which needs attention.
4571  */
4572  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4573  continue; /* wrong relation id */
4574  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4575  continue; /* wrong database id */
4576 
4577  /*
4578  * Loop through locks for this target and flag conflicts.
4579  */
4580  predlock = (PREDICATELOCK *)
4581  SHMQueueNext(&(target->predicateLocks),
4582  &(target->predicateLocks),
4583  offsetof(PREDICATELOCK, targetLink));
4584  while (predlock)
4585  {
4586  PREDICATELOCK *nextpredlock;
4587 
4588  nextpredlock = (PREDICATELOCK *)
4589  SHMQueueNext(&(target->predicateLocks),
4590  &(predlock->targetLink),
4591  offsetof(PREDICATELOCK, targetLink));
4592 
4593  if (predlock->tag.myXact != MySerializableXact
4595  {
4597  }
4598 
4599  predlock = nextpredlock;
4600  }
4601  }
4602 
4603  /* Release locks in reverse order */
4604  LWLockRelease(SerializableXactHashLock);
4605  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4607  LWLockRelease(SerializablePredicateLockListLock);
4608 }
#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:4618
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:732
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:655
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:121

◆ CheckTargetForConflictsIn()

static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag)
static

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

4261 {
4262  uint32 targettaghash;
4263  LWLock *partitionLock;
4264  PREDICATELOCKTARGET *target;
4265  PREDICATELOCK *predlock;
4266  PREDICATELOCK *mypredlock = NULL;
4267  PREDICATELOCKTAG mypredlocktag;
4268 
4270 
4271  /*
4272  * The same hash and LW lock apply to the lock target and the lock itself.
4273  */
4274  targettaghash = PredicateLockTargetTagHashCode(targettag);
4275  partitionLock = PredicateLockHashPartitionLock(targettaghash);
4276  LWLockAcquire(partitionLock, LW_SHARED);
4277  target = (PREDICATELOCKTARGET *)
4279  targettag, targettaghash,
4280  HASH_FIND, NULL);
4281  if (!target)
4282  {
4283  /* Nothing has this target locked; we're done here. */
4284  LWLockRelease(partitionLock);
4285  return;
4286  }
4287 
4288  /*
4289  * Each lock for an overlapping transaction represents a conflict: a
4290  * rw-dependency in to this transaction.
4291  */
4292  predlock = (PREDICATELOCK *)
4293  SHMQueueNext(&(target->predicateLocks),
4294  &(target->predicateLocks),
4295  offsetof(PREDICATELOCK, targetLink));
4296  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4297  while (predlock)
4298  {
4299  SHM_QUEUE *predlocktargetlink;
4300  PREDICATELOCK *nextpredlock;
4301  SERIALIZABLEXACT *sxact;
4302 
4303  predlocktargetlink = &(predlock->targetLink);
4304  nextpredlock = (PREDICATELOCK *)
4305  SHMQueueNext(&(target->predicateLocks),
4306  predlocktargetlink,
4307  offsetof(PREDICATELOCK, targetLink));
4308 
4309  sxact = predlock->tag.myXact;
4310  if (sxact == MySerializableXact)
4311  {
4312  /*
4313  * If we're getting a write lock on a tuple, we don't need a
4314  * predicate (SIREAD) lock on the same tuple. We can safely remove
4315  * our SIREAD lock, but we'll defer doing so until after the loop
4316  * because that requires upgrading to an exclusive partition lock.
4317  *
4318  * We can't use this optimization within a subtransaction because
4319  * the subtransaction could roll back, and we would be left
4320  * without any lock at the top level.
4321  */
4322  if (!IsSubTransaction()
4323  && GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
4324  {
4325  mypredlock = predlock;
4326  mypredlocktag = predlock->tag;
4327  }
4328  }
4329  else if (!SxactIsDoomed(sxact)
4330  && (!SxactIsCommitted(sxact)
4332  sxact->finishedBefore))
4334  {
4335  LWLockRelease(SerializableXactHashLock);
4336  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4337 
4338  /*
4339  * Re-check after getting exclusive lock because the other
4340  * transaction may have flagged a conflict.
4341  */
4342  if (!SxactIsDoomed(sxact)
4343  && (!SxactIsCommitted(sxact)
4345  sxact->finishedBefore))
4347  {
4349  }
4350 
4351  LWLockRelease(SerializableXactHashLock);
4352  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4353  }
4354 
4355  predlock = nextpredlock;
4356  }
4357  LWLockRelease(SerializableXactHashLock);
4358  LWLockRelease(partitionLock);
4359 
4360  /*
4361  * If we found one of our own SIREAD locks to remove, remove it now.
4362  *
4363  * At this point our transaction already has a RowExclusiveLock on the
4364  * relation, so we are OK to drop the predicate lock on the tuple, if
4365  * found, without fearing that another write against the tuple will occur
4366  * before the MVCC information makes it to the buffer.
4367  */
4368  if (mypredlock != NULL)
4369  {
4370  uint32 predlockhashcode;
4371  PREDICATELOCK *rmpredlock;
4372 
4373  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
4374  if (IsInParallelMode())
4376  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4377  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4378 
4379  /*
4380  * Remove the predicate lock from shared memory, if it wasn't removed
4381  * while the locks were released. One way that could happen is from
4382  * autovacuum cleaning up an index.
4383  */
4384  predlockhashcode = PredicateLockHashCodeFromTargetHashCode
4385  (&mypredlocktag, targettaghash);
4386  rmpredlock = (PREDICATELOCK *)
4388  &mypredlocktag,
4389  predlockhashcode,
4390  HASH_FIND, NULL);
4391  if (rmpredlock != NULL)
4392  {
4393  Assert(rmpredlock == mypredlock);
4394 
4395  SHMQueueDelete(&(mypredlock->targetLink));
4396  SHMQueueDelete(&(mypredlock->xactLink));
4397 
4398  rmpredlock = (PREDICATELOCK *)
4400  &mypredlocktag,
4401  predlockhashcode,
4402  HASH_REMOVE, NULL);
4403  Assert(rmpredlock == mypredlock);
4404 
4405  RemoveTargetIfNoLongerUsed(target, targettaghash);
4406  }
4407 
4408  LWLockRelease(SerializableXactHashLock);
4409  LWLockRelease(partitionLock);
4410  if (IsInParallelMode())
4412  LWLockRelease(SerializablePredicateLockListLock);
4413 
4414  if (rmpredlock != NULL)
4415  {
4416  /*
4417  * Remove entry in local lock table if it exists. It's OK if it
4418  * doesn't exist; that means the lock was transferred to a new
4419  * target by a different backend.
4420  */
4422  targettag, targettaghash,
4423  HASH_REMOVE, NULL);
4424 
4425  DecrementParentLocks(targettag);
4426  }
4427  }
4428 }
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:4618
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:994
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:314
static HTAB * PredicateLockHash
Definition: predicate.c:396
#define InvalidSerializableXact
unsigned int uint32
Definition: c.h:358
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:732
static HTAB * LocalPredicateLockHash
Definition: predicate.c:412
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
bool IsSubTransaction(void)
Definition: xact.c:4706
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:655

◆ ClearOldPredicateLocks()

static void ClearOldPredicateLocks ( void  )
static

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

3695 {
3696  SERIALIZABLEXACT *finishedSxact;
3697  PREDICATELOCK *predlock;
3698 
3699  /*
3700  * Loop through finished transactions. They are in commit order, so we can
3701  * stop as soon as we find one that's still interesting.
3702  */
3703  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3704  finishedSxact = (SERIALIZABLEXACT *)
3707  offsetof(SERIALIZABLEXACT, finishedLink));
3708  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3709  while (finishedSxact)
3710  {
3711  SERIALIZABLEXACT *nextSxact;
3712 
3713  nextSxact = (SERIALIZABLEXACT *)
3715  &(finishedSxact->finishedLink),
3716  offsetof(SERIALIZABLEXACT, finishedLink));
3720  {
3721  /*
3722  * This transaction committed before any in-progress transaction
3723  * took its snapshot. It's no longer interesting.
3724  */
3725  LWLockRelease(SerializableXactHashLock);
3726  SHMQueueDelete(&(finishedSxact->finishedLink));
3727  ReleaseOneSerializableXact(finishedSxact, false, false);
3728  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3729  }
3730  else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3731  && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3732  {
3733  /*
3734  * Any active transactions that took their snapshot before this
3735  * transaction committed are read-only, so we can clear part of
3736  * its state.
3737  */
3738  LWLockRelease(SerializableXactHashLock);
3739 
3740  if (SxactIsReadOnly(finishedSxact))
3741  {
3742  /* A read-only transaction can be removed entirely */
3743  SHMQueueDelete(&(finishedSxact->finishedLink));
3744  ReleaseOneSerializableXact(finishedSxact, false, false);
3745  }
3746  else
3747  {
3748  /*
3749  * A read-write transaction can only be partially cleared. We
3750  * need to keep the SERIALIZABLEXACT but can release the
3751  * SIREAD locks and conflicts in.
3752  */
3753  ReleaseOneSerializableXact(finishedSxact, true, false);
3754  }
3755 
3757  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3758  }
3759  else
3760  {
3761  /* Still interesting. */
3762  break;
3763  }
3764  finishedSxact = nextSxact;
3765  }
3766  LWLockRelease(SerializableXactHashLock);
3767 
3768  /*
3769  * Loop through predicate locks on dummy transaction for summarized data.
3770  */
3771  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
3772  predlock = (PREDICATELOCK *)
3775  offsetof(PREDICATELOCK, xactLink));
3776  while (predlock)
3777  {
3778  PREDICATELOCK *nextpredlock;
3779  bool canDoPartialCleanup;
3780 
3781  nextpredlock = (PREDICATELOCK *)
3783  &predlock->xactLink,
3784  offsetof(PREDICATELOCK, xactLink));
3785 
3786  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3787  Assert(predlock->commitSeqNo != 0);
3789  canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
3790  LWLockRelease(SerializableXactHashLock);
3791 
3792  /*
3793  * If this lock originally belonged to an old enough transaction, we
3794  * can release it.
3795  */
3796  if (canDoPartialCleanup)
3797  {
3798  PREDICATELOCKTAG tag;
3799  PREDICATELOCKTARGET *target;
3800  PREDICATELOCKTARGETTAG targettag;
3801  uint32 targettaghash;
3802  LWLock *partitionLock;
3803 
3804  tag = predlock->tag;
3805  target = tag.myTarget;
3806  targettag = target->tag;
3807  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3808  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3809 
3810  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3811 
3812  SHMQueueDelete(&(predlock->targetLink));
3813  SHMQueueDelete(&(predlock->xactLink));
3814 
3817  targettaghash),
3818  HASH_REMOVE, NULL);
3819  RemoveTargetIfNoLongerUsed(target, targettaghash);
3820 
3821  LWLockRelease(partitionLock);
3822  }
3823 
3824  predlock = nextpredlock;
3825  }
3826 
3827  LWLockRelease(SerializablePredicateLockListLock);
3828  LWLockRelease(SerializableFinishedListLock);
3829 }
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:358
#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:3851
#define Assert(condition)
Definition: c.h:732
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:655
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:955
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:732
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:974
int errcode(int sqlerrcode)
Definition: elog.c:570
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:994
#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:784
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:655

◆ 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:358
#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:732
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:994
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:314
static HTAB * PredicateLockHash
Definition: predicate.c:396
unsigned int uint32
Definition: c.h:358
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:732
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:655
PREDICATELOCKTARGET * myTarget

◆ DeleteLockTarget()

static void DeleteLockTarget ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

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

2614 {
2615  PREDICATELOCK *predlock;
2616  SHM_QUEUE *predlocktargetlink;
2617  PREDICATELOCK *nextpredlock;
2618  bool found;
2619 
2620  Assert(LWLockHeldByMeInMode(SerializablePredicateLockListLock,
2621  LW_EXCLUSIVE));
2623 
2624  predlock = (PREDICATELOCK *)
2625  SHMQueueNext(&(target->predicateLocks),
2626  &(target->predicateLocks),
2627  offsetof(PREDICATELOCK, targetLink));
2628  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2629  while (predlock)
2630  {
2631  predlocktargetlink = &(predlock->targetLink);
2632  nextpredlock = (PREDICATELOCK *)
2633  SHMQueueNext(&(target->predicateLocks),
2634  predlocktargetlink,
2635  offsetof(PREDICATELOCK, targetLink));
2636 
2637  SHMQueueDelete(&(predlock->xactLink));
2638  SHMQueueDelete(&(predlock->targetLink));
2639 
2642  &predlock->tag,
2644  targettaghash),
2645  HASH_REMOVE, &found);
2646  Assert(found);
2647 
2648  predlock = nextpredlock;
2649  }
2650  LWLockRelease(SerializableXactHashLock);
2651 
2652  /* Remove the target itself, if possible. */
2653  RemoveTargetIfNoLongerUsed(target, targettaghash);
2654 }
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:732
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:655

◆ DropAllPredicateLocksFromTable()

static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
)
static

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

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

◆ FlagRWConflict()

static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

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

4619 {
4620  Assert(reader != writer);
4621 
4622  /* First, see if this conflict causes failure. */
4624 
4625  /* Actually do the conflict flagging. */
4626  if (reader == OldCommittedSxact)
4628  else if (writer == OldCommittedSxact)
4630  else
4631  SetRWConflict(reader, writer);
4632 }
#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:4653
#define Assert(condition)
Definition: c.h:732
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:732
#define SXACT_FLAG_RO_UNSAFE
#define offsetof(type, field)
Definition: c.h:655
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:732

◆ 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:732
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:924
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:81
int errcode(int sqlerrcode)
Definition: elog.c:570
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3283
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:1799
bool SHMQueueEmpty(const SHM_QUEUE *queue)
Definition: shmqueue.c:180
bool XactReadOnly
Definition: xact.c:78
#define Assert(condition)
Definition: c.h:732
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
int errmsg(const char *fmt,...)
Definition: elog.c:784
#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:655
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:81
int errhint(const char *fmt,...)
Definition: elog.c:974
static Snapshot GetSafeSnapshot(Snapshot snapshot)
Definition: predicate.c:1491
int errcode(int sqlerrcode)
Definition: elog.c:570
bool RecoveryInProgress(void)
Definition: xlog.c:7898
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:860
#define ereport(elevel, rest)
Definition: elog.h:141
bool XactReadOnly
Definition: xact.c:78
#define Assert(condition)
Definition: c.h:732
int errmsg(const char *fmt,...)
Definition: elog.c:784
#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:68
static PredXactList PredXact
Definition: predicate.c:382
TransactionId SxactGlobalXmin
int errcode(int sqlerrcode)
Definition: elog.c:570
bool RecoveryInProgress(void)
Definition: xlog.c:7898
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define SxactIsDoomed(sxact)
Definition: predicate.c:278
bool IsInParallelMode(void)
Definition: xact.c:994
SHM_QUEUE possibleUnsafeConflicts
#define ERROR
Definition: elog.h:43
int max_prepared_xacts
Definition: twophase.c:118
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:860
#define InvalidTransactionId
Definition: transam.h:31
TransactionId xmin
Definition: snapshot.h:157
SerCommitSeqNo lastCommitBeforeSnapshot
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:410
#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:78
#define Assert(condition)
Definition: c.h:732
static void OldSerXidSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:967
SerCommitSeqNo prepareSeqNo
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:1503
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:784
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:226
#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:1794
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:955
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:118
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:732
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:77
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
SerCommitSeqNo prepareSeqNo
size_t Size
Definition: c.h:466
SerCommitSeqNo LastSxactCommitSeqNo
SERIALIZABLEXACT * OldCommittedSxact
#define HASH_FIXED_SIZE
Definition: hsearch.h:96
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c: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:732
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:732
struct PredXactListElementData * PredXactListElement
#define offsetof(type, field)
Definition: c.h:655

◆ 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:507
#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:375
TransactionId headXid
Definition: predicate.c:346
#define Assert(condition)
Definition: c.h:732
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:263
#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:507
#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:467
uint64 SerCommitSeqNo
#define Assert(condition)
Definition: c.h:732
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:732
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:165

◆ 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:732

◆ 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:7898
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:732
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 4653 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().

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

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

Referenced by PrepareTransaction().

4999 {
5001  return;
5002 
5004 
5005  MySerializableXact->pid = 0;
5006 
5008  LocalPredicateLockHash = NULL;
5009 
5011  MyXactDidWrite = false;
5012 }
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:732
static HTAB * LocalPredicateLockHash
Definition: predicate.c:412
static bool MyXactDidWrite
Definition: predicate.c:420

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

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

4829 {
4830  RWConflict nearConflict;
4831 
4833  return;
4834 
4836 
4837  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4838 
4839  /* Check if someone else has already decided that we need to die */
4841  {
4843  LWLockRelease(SerializableXactHashLock);
4844  ereport(ERROR,
4845  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4846  errmsg("could not serialize access due to read/write dependencies among transactions"),
4847  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4848  errhint("The transaction might succeed if retried.")));
4849  }
4850 
4851  nearConflict = (RWConflict)
4854  offsetof(RWConflictData, inLink));
4855  while (nearConflict)
4856  {
4857  if (!SxactIsCommitted(nearConflict->sxactOut)
4858  && !SxactIsDoomed(nearConflict->sxactOut))
4859  {
4860  RWConflict farConflict;
4861 
4862  farConflict = (RWConflict)
4863  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4864  &nearConflict->sxactOut->inConflicts,
4865  offsetof(RWConflictData, inLink));
4866  while (farConflict)
4867  {
4868  if (farConflict->sxactOut == MySerializableXact
4869  || (!SxactIsCommitted(farConflict->sxactOut)
4870  && !SxactIsReadOnly(farConflict->sxactOut)
4871  && !SxactIsDoomed(farConflict->sxactOut)))
4872  {
4873  /*
4874  * Normally, we kill the pivot transaction to make sure we
4875  * make progress if the failing transaction is retried.
4876  * However, we can't kill it if it's already prepared, so
4877  * in that case we commit suicide instead.
4878  */
4879  if (SxactIsPrepared(nearConflict->sxactOut))
4880  {
4881  LWLockRelease(SerializableXactHashLock);
4882  ereport(ERROR,
4883  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4884  errmsg("could not serialize access due to read/write dependencies among transactions"),
4885  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4886  errhint("The transaction might succeed if retried.")));
4887  }
4888  nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4889  break;
4890  }
4891  farConflict = (RWConflict)
4892  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4893  &farConflict->inLink,
4894  offsetof(RWConflictData, inLink));
4895  }
4896  }
4897 
4898  nearConflict = (RWConflict)
4900  &nearConflict->inLink,
4901  offsetof(RWConflictData, inLink));
4902  }
4903 
4906 
4907  LWLockRelease(SerializableXactHashLock);
4908 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:279
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:419
int errhint(const char *fmt,...)
Definition: elog.c:974
static PredXactList PredXact
Definition: predicate.c:382
struct RWConflictData * RWConflict
int errcode(int sqlerrcode)
Definition: elog.c:570
#define SxactIsPrepared(sxact)
Definition: predicate.c:276
int errdetail_internal(const char *fmt,...)
Definition: elog.c:887
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:732
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:784
#define IsolationIsSerializable()
Definition: xact.h:52
#define SxactIsCommitted(sxact)
Definition: predicate.c:275
#define offsetof(type, field)
Definition: c.h:655
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:358
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:301
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:732
PREDICATELOCKTARGET * myTarget

◆ predicatelock_twophase_recover()

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

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

5049 {
5050  TwoPhasePredicateRecord *record;
5051 
5052  Assert(len == sizeof(TwoPhasePredicateRecord));
5053 
5054  record = (TwoPhasePredicateRecord *) recdata;
5055 
5056  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
5057  (record->type == TWOPHASEPREDICATERECORD_LOCK));
5058 
5059  if (record->type == TWOPHASEPREDICATERECORD_XACT)
5060  {
5061  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
5062  TwoPhasePredicateXactRecord *xactRecord;
5063  SERIALIZABLEXACT *sxact;
5064  SERIALIZABLEXID *sxid;
5065  SERIALIZABLEXIDTAG sxidtag;
5066  bool found;
5067 
5068  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
5069 
5070  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
5071  sxact = CreatePredXact();
5072  if (!sxact)
5073  ereport(ERROR,
5074  (errcode(ERRCODE_OUT_OF_MEMORY),
5075  errmsg("out of shared memory")));
5076 
5077  /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
5078  sxact->vxid.backendId = InvalidBackendId;
5080  sxact->pid = 0;
5081 
5082  /* a prepared xact hasn't committed yet */
5086 
5088 
5089  /*
5090  * Don't need to track this; no transactions running at the time the
5091  * recovered xact started are still active, except possibly other
5092  * prepared xacts and we don't care whether those are RO_SAFE or not.
5093  */
5095 
5096  SHMQueueInit(&(sxact->predicateLocks));
5097  SHMQueueElemInit(&(sxact->finishedLink));
5098 
5099  sxact->topXid = xid;
5100  sxact->xmin = xactRecord->xmin;
5101  sxact->flags = xactRecord->flags;
5102  Assert(SxactIsPrepared(sxact));
5103  if (!SxactIsReadOnly(sxact))
5104  {
5108  }
5109 
5110  /*
5111  * We don't know whether the transaction had any conflicts or not, so
5112  * we'll conservatively assume that it had both a conflict in and a
5113  * conflict out, and represent that with the summary conflict flags.
5114  */
5115  SHMQueueInit(&(sxact->outConflicts));
5116  SHMQueueInit(&(sxact->inConflicts));
5119 
5120  /* Register the transaction's xid */
5121  sxidtag.xid = xid;
5123  &sxidtag,
5124  HASH_ENTER, &found);
5125  Assert(sxid != NULL);
5126  Assert(!found);
5127  sxid->myXact = (SERIALIZABLEXACT *) sxact;
5128 
5129  /*
5130  * Update global xmin. Note that this is a special case compared to
5131  * registering a normal transaction, because the global xmin might go
5132  * backwards. That's OK, because until recovery is over we're not
5133  * going to complete any transactions or create any non-prepared
5134  * transactions, so there's no danger of throwing away.
5135  */
5138  {
5139  PredXact->SxactGlobalXmin = sxact->xmin;
5142  }
5143  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
5144  {
5147  }
5148 
5149  LWLockRelease(SerializableXactHashLock);
5150  }
5151  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
5152  {
5153  /* Lock record. Recreate the PREDICATELOCK */
5154  TwoPhasePredicateLockRecord *lockRecord;
5155  SERIALIZABLEXID *sxid;
5156  SERIALIZABLEXACT *sxact;
5157  SERIALIZABLEXIDTAG sxidtag;
5158  uint32 targettaghash;
5159 
5160  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
5161  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
5162 
5163  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
5164  sxidtag.xid = xid;
5165  sxid = (SERIALIZABLEXID *)
5166  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
5167  LWLockRelease(SerializableXactHashLock);
5168 
5169  Assert(sxid != NULL);
5170  sxact = sxid->myXact;
5171  Assert(sxact != InvalidSerializableXact);
5172 
5173  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5174  }
5175 }
#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 PredXact