PostgreSQL Source Code  git master
predicate.c File Reference
#include "postgres.h"
#include "access/htup_details.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 "utils/tqual.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 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 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)
 
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)
 

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
 

Macro Definition Documentation

◆ NPREDICATELOCKTARGETENTS

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

Definition at line 253 of file predicate.c.

Referenced by InitPredicateLocks(), and PredicateLockShmemSize().

◆ OLDSERXID_ENTRIESPERPAGE

#define OLDSERXID_ENTRIESPERPAGE   (OLDSERXID_PAGESIZE / OLDSERXID_ENTRYSIZE)

Definition at line 318 of file predicate.c.

◆ OLDSERXID_ENTRYSIZE

#define OLDSERXID_ENTRYSIZE   sizeof(SerCommitSeqNo)

Definition at line 317 of file predicate.c.

◆ OLDSERXID_MAX_PAGE

#define OLDSERXID_MAX_PAGE   (MaxTransactionId / OLDSERXID_ENTRIESPERPAGE)

Definition at line 323 of file predicate.c.

Referenced by OldSerXidPagePrecedesLogically().

◆ OLDSERXID_PAGESIZE

#define OLDSERXID_PAGESIZE   BLCKSZ

Definition at line 316 of file predicate.c.

◆ OldSerXidNextPage

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

Definition at line 325 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:317
#define OldSerXidSlruCtl
Definition: predicate.c:314
#define OLDSERXID_ENTRIESPERPAGE
Definition: predicate.c:318
unsigned int uint32
Definition: c.h:325
uint64 SerCommitSeqNo

Definition at line 327 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 245 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 279 of file predicate.c.

Referenced by GetSafeSnapshotBlockingPids(), and ReleasePredicateLocks().

◆ SxactIsDoomed

◆ SxactIsOnFinishedList

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

Definition at line 256 of file predicate.c.

Referenced by ReleaseOneSerializableXact(), 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 281 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 222 of file predicate.c.

Referenced by DeleteChildTargetLocks().

Typedef Documentation

◆ OldSerXidControl

Definition at line 340 of file predicate.c.

◆ OldSerXidControlData

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4759 of file predicate.c.

References TwoPhasePredicateRecord::data, SERIALIZABLEXACT::flags, TwoPhasePredicateXactRecord::flags, InvalidSerializableXact, TwoPhasePredicateRecord::lockRecord, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myTarget, offsetof, 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().

4760 {
4761  PREDICATELOCK *predlock;
4762  SERIALIZABLEXACT *sxact;
4763  TwoPhasePredicateRecord record;
4764  TwoPhasePredicateXactRecord *xactRecord;
4765  TwoPhasePredicateLockRecord *lockRecord;
4766 
4767  sxact = MySerializableXact;
4768  xactRecord = &(record.data.xactRecord);
4769  lockRecord = &(record.data.lockRecord);
4770 
4772  return;
4773 
4774  /* Generate an xact record for our SERIALIZABLEXACT */
4776  xactRecord->xmin = MySerializableXact->xmin;
4777  xactRecord->flags = MySerializableXact->flags;
4778 
4779  /*
4780  * Note that we don't include the list of conflicts in our out in the
4781  * statefile, because new conflicts can be added even after the
4782  * transaction prepares. We'll just make a conservative assumption during
4783  * recovery instead.
4784  */
4785 
4787  &record, sizeof(record));
4788 
4789  /*
4790  * Generate a lock record for each lock.
4791  *
4792  * To do this, we need to walk the predicate lock list in our sxact rather
4793  * than using the local predicate lock table because the latter is not
4794  * guaranteed to be accurate.
4795  */
4796  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
4797 
4798  predlock = (PREDICATELOCK *)
4799  SHMQueueNext(&(sxact->predicateLocks),
4800  &(sxact->predicateLocks),
4801  offsetof(PREDICATELOCK, xactLink));
4802 
4803  while (predlock != NULL)
4804  {
4806  lockRecord->target = predlock->tag.myTarget->tag;
4807 
4809  &record, sizeof(record));
4810 
4811  predlock = (PREDICATELOCK *)
4812  SHMQueueNext(&(sxact->predicateLocks),
4813  &(predlock->xactLink),
4814  offsetof(PREDICATELOCK, xactLink));
4815  }
4816 
4817  LWLockRelease(SerializablePredicateLockListLock);
4818 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:409
TwoPhasePredicateRecordType type
PREDICATELOCKTARGETTAG target
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1191
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define TWOPHASE_RM_PREDICATELOCK_ID
Definition: twophase_rmgr.h:28
TwoPhasePredicateXactRecord xactRecord
#define InvalidSerializableXact
PREDICATELOCKTAG tag
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
union TwoPhasePredicateRecord::@111 data
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
TwoPhasePredicateLockRecord lockRecord
#define offsetof(type, field)
Definition: c.h:622
PREDICATELOCKTARGET * myTarget

◆ CheckAndPromotePredicateLockRequest()

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2205 of file predicate.c.

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

Referenced by PredicateLockAcquire().

2206 {
2207  PREDICATELOCKTARGETTAG targettag,
2208  nexttag,
2209  promotiontag;
2210  LOCALPREDICATELOCK *parentlock;
2211  bool found,
2212  promote;
2213 
2214  promote = false;
2215 
2216  targettag = *reqtag;
2217 
2218  /* check parents iteratively */
2219  while (GetParentPredicateLockTag(&targettag, &nexttag))
2220  {
2221  targettag = nexttag;
2223  &targettag,
2224  HASH_ENTER,
2225  &found);
2226  if (!found)
2227  {
2228  parentlock->held = false;
2229  parentlock->childLocks = 1;
2230  }
2231  else
2232  parentlock->childLocks++;
2233 
2234  if (parentlock->childLocks >
2235  MaxPredicateChildLocks(&targettag))
2236  {
2237  /*
2238  * We should promote to this parent lock. Continue to check its
2239  * ancestors, however, both to get their child counts right and to
2240  * check whether we should just go ahead and promote to one of
2241  * them.
2242  */
2243  promotiontag = targettag;
2244  promote = true;
2245  }
2246  }
2247 
2248  if (promote)
2249  {
2250  /* acquire coarsest ancestor eligible for promotion */
2251  PredicateLockAcquire(&promotiontag);
2252  return true;
2253  }
2254  else
2255  return false;
2256 }
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:2393
static int MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag)
Definition: predicate.c:2168
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:1947
static HTAB * LocalPredicateLockHash
Definition: predicate.c:402

◆ CheckForSerializableConflictIn()

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

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

4282 {
4283  PREDICATELOCKTARGETTAG targettag;
4284 
4285  if (!SerializationNeededForWrite(relation))
4286  return;
4287 
4288  /* Check if someone else has already decided that we need to die */
4290  ereport(ERROR,
4291  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4292  errmsg("could not serialize access due to read/write dependencies among transactions"),
4293  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4294  errhint("The transaction might succeed if retried.")));
4295 
4296  /*
4297  * We're doing a write which might cause rw-conflicts now or later.
4298  * Memorize that fact.
4299  */
4300  MyXactDidWrite = true;
4301 
4302  /*
4303  * It is important that we check for locks from the finest granularity to
4304  * the coarsest granularity, so that granularity promotion doesn't cause
4305  * us to miss a lock. The new (coarser) lock will be acquired before the
4306  * old (finer) locks are released.
4307  *
4308  * It is not possible to take and hold a lock across the checks for all
4309  * granularities because each target could be in a separate partition.
4310  */
4311  if (tuple != NULL)
4312  {
4314  relation->rd_node.dbNode,
4315  relation->rd_id,
4316  ItemPointerGetBlockNumber(&(tuple->t_self)),
4317  ItemPointerGetOffsetNumber(&(tuple->t_self)));
4318  CheckTargetForConflictsIn(&targettag);
4319  }
4320 
4321  if (BufferIsValid(buffer))
4322  {
4324  relation->rd_node.dbNode,
4325  relation->rd_id,
4327  CheckTargetForConflictsIn(&targettag);
4328  }
4329 
4331  relation->rd_node.dbNode,
4332  relation->rd_id);
4333  CheckTargetForConflictsIn(&targettag);
4334 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:409
int errhint(const char *fmt,...)
Definition: elog.c:987
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4102
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
int errcode(int sqlerrcode)
Definition: elog.c:575
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:540
#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:900
#define SxactIsDoomed(sxact)
Definition: predicate.c:269
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define ereport(elevel, rest)
Definition: elog.h:122
Oid rd_id
Definition: rel.h:86
RelFileNode rd_node
Definition: rel.h:55
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
int errmsg(const char *fmt,...)
Definition: elog.c:797
static bool MyXactDidWrite
Definition: predicate.c:410
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98

◆ CheckForSerializableConflictOut()

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

Definition at line 3899 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 bitgetpage(), heap_fetch(), heap_get_latest_tid(), heap_hot_search_buffer(), heapgetpage(), heapgettup(), and tablesample_getnext().

3902 {
3903  TransactionId xid;
3904  SERIALIZABLEXIDTAG sxidtag;
3905  SERIALIZABLEXID *sxid;
3906  SERIALIZABLEXACT *sxact;
3907  HTSV_Result htsvResult;
3908 
3909  if (!SerializationNeededForRead(relation, snapshot))
3910  return;
3911 
3912  /* Check if someone else has already decided that we need to die */
3914  {
3915  ereport(ERROR,
3916  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
3917  errmsg("could not serialize access due to read/write dependencies among transactions"),
3918  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
3919  errhint("The transaction might succeed if retried.")));
3920  }
3921 
3922  /*
3923  * Check to see whether the tuple has been written to by a concurrent
3924  * transaction, either to create it not visible to us, or to delete it
3925  * while it is visible to us. The "visible" bool indicates whether the
3926  * tuple is visible to us, while HeapTupleSatisfiesVacuum checks what else
3927  * is going on with it.
3928  */
3929  htsvResult = HeapTupleSatisfiesVacuum(tuple, TransactionXmin, buffer);
3930  switch (htsvResult)
3931  {
3932  case HEAPTUPLE_LIVE:
3933  if (visible)
3934  return;
3935  xid = HeapTupleHeaderGetXmin(tuple->t_data);
3936  break;
3938  if (!visible)
3939  return;
3940  xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
3941  break;
3943  xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
3944  break;
3946  xid = HeapTupleHeaderGetXmin(tuple->t_data);
3947  break;
3948  case HEAPTUPLE_DEAD:
3949  return;
3950  default:
3951 
3952  /*
3953  * The only way to get to this default clause is if a new value is
3954  * added to the enum type without adding it to this switch
3955  * statement. That's a bug, so elog.
3956  */
3957  elog(ERROR, "unrecognized return value from HeapTupleSatisfiesVacuum: %u", htsvResult);
3958 
3959  /*
3960  * In spite of having all enum values covered and calling elog on
3961  * this default, some compilers think this is a code path which
3962  * allows xid to be used below without initialization. Silence
3963  * that warning.
3964  */
3965  xid = InvalidTransactionId;
3966  }
3969 
3970  /*
3971  * Find top level xid. Bail out if xid is too early to be a conflict, or
3972  * if it's our own xid.
3973  */
3975  return;
3976  xid = SubTransGetTopmostTransaction(xid);
3978  return;
3980  return;
3981 
3982  /*
3983  * Find sxact or summarized info for the top level xid.
3984  */
3985  sxidtag.xid = xid;
3986  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3987  sxid = (SERIALIZABLEXID *)
3988  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
3989  if (!sxid)
3990  {
3991  /*
3992  * Transaction not found in "normal" SSI structures. Check whether it
3993  * got pushed out to SLRU storage for "old committed" transactions.
3994  */
3995  SerCommitSeqNo conflictCommitSeqNo;
3996 
3997  conflictCommitSeqNo = OldSerXidGetMinConflictCommitSeqNo(xid);
3998  if (conflictCommitSeqNo != 0)
3999  {
4000  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4002  || conflictCommitSeqNo
4004  ereport(ERROR,
4005  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4006  errmsg("could not serialize access due to read/write dependencies among transactions"),
4007  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4008  errhint("The transaction might succeed if retried.")));
4009 
4012  ereport(ERROR,
4013  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4014  errmsg("could not serialize access due to read/write dependencies among transactions"),
4015  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4016  errhint("The transaction might succeed if retried.")));
4017 
4019  }
4020 
4021  /* It's not serializable or otherwise not important. */
4022  LWLockRelease(SerializableXactHashLock);
4023  return;
4024  }
4025  sxact = sxid->myXact;
4026  Assert(TransactionIdEquals(sxact->topXid, xid));
4027  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4028  {
4029  /* Can't conflict with ourself or a transaction that will roll back. */
4030  LWLockRelease(SerializableXactHashLock);
4031  return;
4032  }
4033 
4034  /*
4035  * We have a conflict out to a transaction which has a conflict out to a
4036  * summarized transaction. That summarized transaction must have
4037  * committed first, and we can't tell when it committed in relation to our
4038  * snapshot acquisition, so something needs to be canceled.
4039  */
4040  if (SxactHasSummaryConflictOut(sxact))
4041  {
4042  if (!SxactIsPrepared(sxact))
4043  {
4044  sxact->flags |= SXACT_FLAG_DOOMED;
4045  LWLockRelease(SerializableXactHashLock);
4046  return;
4047  }
4048  else
4049  {
4050  LWLockRelease(SerializableXactHashLock);
4051  ereport(ERROR,
4052  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4053  errmsg("could not serialize access due to read/write dependencies among transactions"),
4054  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4055  errhint("The transaction might succeed if retried.")));
4056  }
4057  }
4058 
4059  /*
4060  * If this is a read-only transaction and the writing transaction has
4061  * committed, and it doesn't have a rw-conflict to a transaction which
4062  * committed before it, no conflict.
4063  */
4065  && SxactIsCommitted(sxact)
4066  && !SxactHasSummaryConflictOut(sxact)
4067  && (!SxactHasConflictOut(sxact)
4069  {
4070  /* Read-only transaction will appear to run first. No conflict. */
4071  LWLockRelease(SerializableXactHashLock);
4072  return;
4073  }
4074 
4075  if (!XidIsConcurrent(xid))
4076  {
4077  /* This write was already in our snapshot; no conflict. */
4078  LWLockRelease(SerializableXactHashLock);
4079  return;
4080  }
4081 
4083  {
4084  /* We don't want duplicate conflict records in the list. */
4085  LWLockRelease(SerializableXactHashLock);
4086  return;
4087  }
4088 
4089  /*
4090  * Flag the conflict. But first, if this conflict creates a dangerous
4091  * structure, ereport an error.
4092  */
4094  LWLockRelease(SerializableXactHashLock);
4095 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:364
#define SxactIsReadOnly(sxact)
Definition: predicate.c:270
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:409
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:635
int errhint(const char *fmt,...)
Definition: elog.c:987
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4456
uint32 TransactionId
Definition: c.h:474
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:271
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
Definition: subtrans.c:150
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:3856
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
Definition: tqual.c:1164
int errcode(int sqlerrcode)
Definition: elog.c:575
static HTAB * SerializableXidHash
Definition: predicate.c:384
SERIALIZABLEXACT * myXact
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
#define SxactIsPrepared(sxact)
Definition: predicate.c:267
HTSV_Result
Definition: tqual.h:49
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
TransactionId TransactionXmin
Definition: snapmgr.c:164
HeapTupleHeader t_data
Definition: htup.h:68
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define SxactIsDoomed(sxact)
Definition: predicate.c:269
#define ERROR
Definition: elog.h:43
#define InvalidTransactionId
Definition: transam.h:31
SerCommitSeqNo lastCommitBeforeSnapshot
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:404
#define ereport(elevel, rest)
Definition: elog.h:122
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:272
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define InvalidSerCommitSeqNo
union SERIALIZABLEXACT::@110 SeqNo
bool SHMQueueEmpty(const SHM_QUEUE *queue)
Definition: shmqueue.c:180
SerCommitSeqNo earliestOutConflictCommit
static SerCommitSeqNo OldSerXidGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:905
uint64 SerCommitSeqNo
#define SXACT_FLAG_DOOMED
#define SxactHasConflictOut(sxact)
Definition: predicate.c:278
#define Assert(condition)
Definition: c.h:699
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:312
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:496
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define SxactIsCommitted(sxact)
Definition: predicate.c:266

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 997 of file predicate.c.

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

Referenced by CheckPointGuts().

998 {
999  int tailPage;
1000 
1001  LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);
1002 
1003  /* Exit quickly if the SLRU is currently not in use. */
1004  if (oldSerXidControl->headPage < 0)
1005  {
1006  LWLockRelease(OldSerXidLock);
1007  return;
1008  }
1009 
1011  {
1012  /* We can truncate the SLRU up to the page containing tailXid */
1013  tailPage = OldSerXidPage(oldSerXidControl->tailXid);
1014  }
1015  else
1016  {
1017  /*
1018  * The SLRU is no longer needed. Truncate to head before we set head
1019  * invalid.
1020  *
1021  * XXX: It's possible that the SLRU is not needed again until XID
1022  * wrap-around has happened, so that the segment containing headPage
1023  * that we leave behind will appear to be new again. In that case it
1024  * won't be removed until XID horizon advances enough to make it
1025  * current again.
1026  */
1027  tailPage = oldSerXidControl->headPage;
1028  oldSerXidControl->headPage = -1;
1029  }
1030 
1031  LWLockRelease(OldSerXidLock);
1032 
1033  /* Truncate away pages that are no longer required */
1035 
1036  /*
1037  * Flush dirty SLRU pages to disk
1038  *
1039  * This is not actually necessary from a correctness point of view. We do
1040  * it merely as a debugging aid.
1041  *
1042  * We're doing this after the truncation to avoid writing pages right
1043  * before deleting the file in which they sit, which would be completely
1044  * pointless.
1045  */
1047 }
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1168
#define OldSerXidPage(xid)
Definition: predicate.c:331
#define OldSerXidSlruCtl
Definition: predicate.c:314
void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1103
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
static OldSerXidControl oldSerXidControl
Definition: predicate.c:342
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId tailXid
Definition: predicate.c:337

◆ CheckTableForSerializableConflictIn()

void CheckTableForSerializableConflictIn ( Relation  relation)

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

4365 {
4366  HASH_SEQ_STATUS seqstat;
4367  PREDICATELOCKTARGET *target;
4368  Oid dbId;
4369  Oid heapId;
4370  int i;
4371 
4372  /*
4373  * Bail out quickly if there are no serializable transactions running.
4374  * It's safe to check this without taking locks because the caller is
4375  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4376  * would matter here can be acquired while that is held.
4377  */
4379  return;
4380 
4381  if (!SerializationNeededForWrite(relation))
4382  return;
4383 
4384  /*
4385  * We're doing a write which might cause rw-conflicts now or later.
4386  * Memorize that fact.
4387  */
4388  MyXactDidWrite = true;
4389 
4390  Assert(relation->rd_index == NULL); /* not an index relation */
4391 
4392  dbId = relation->rd_node.dbNode;
4393  heapId = relation->rd_id;
4394 
4395  LWLockAcquire(SerializablePredicateLockListLock, LW_EXCLUSIVE);
4396  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4398  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4399 
4400  /* Scan through target list */
4402 
4403  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4404  {
4405  PREDICATELOCK *predlock;
4406 
4407  /*
4408  * Check whether this is a target which needs attention.
4409  */
4410  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4411  continue; /* wrong relation id */
4412  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4413  continue; /* wrong database id */
4414 
4415  /*
4416  * Loop through locks for this target and flag conflicts.
4417  */
4418  predlock = (PREDICATELOCK *)
4419  SHMQueueNext(&(target->predicateLocks),
4420  &(target->predicateLocks),
4421  offsetof(PREDICATELOCK, targetLink));
4422  while (predlock)
4423  {
4424  PREDICATELOCK *nextpredlock;
4425 
4426  nextpredlock = (PREDICATELOCK *)
4427  SHMQueueNext(&(target->predicateLocks),
4428  &(predlock->targetLink),
4429  offsetof(PREDICATELOCK, targetLink));
4430 
4431  if (predlock->tag.myXact != MySerializableXact
4433  {
4435  }
4436 
4437  predlock = nextpredlock;
4438  }
4439  }
4440 
4441  /* Release locks in reverse order */
4442  LWLockRelease(SerializableXactHashLock);
4443  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4445  LWLockRelease(SerializablePredicateLockListLock);
4446 }
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:409
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:635
static HTAB * PredicateLockTargetHash
Definition: predicate.c:385
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4456
static PredXactList PredXact
Definition: predicate.c:372
TransactionId SxactGlobalXmin
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:540
unsigned int Oid
Definition: postgres_ext.h:31
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
Form_pg_index rd_index
Definition: rel.h:131
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
Oid rd_id
Definition: rel.h:86
PREDICATELOCKTAG tag
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
RelFileNode rd_node
Definition: rel.h:55
#define Assert(condition)
Definition: c.h:699
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
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:250
int i
SERIALIZABLEXACT * myXact
static bool MyXactDidWrite
Definition: predicate.c:410
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define offsetof(type, field)
Definition: c.h:622
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:121

◆ CheckTargetForConflictsIn()

static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag)
static

Definition at line 4102 of file predicate.c.

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

Referenced by CheckForSerializableConflictIn().

4103 {
4104  uint32 targettaghash;
4105  LWLock *partitionLock;
4106  PREDICATELOCKTARGET *target;
4107  PREDICATELOCK *predlock;
4108  PREDICATELOCK *mypredlock = NULL;
4109  PREDICATELOCKTAG mypredlocktag;
4110 
4112 
4113  /*
4114  * The same hash and LW lock apply to the lock target and the lock itself.
4115  */
4116  targettaghash = PredicateLockTargetTagHashCode(targettag);
4117  partitionLock = PredicateLockHashPartitionLock(targettaghash);
4118  LWLockAcquire(partitionLock, LW_SHARED);
4119  target = (PREDICATELOCKTARGET *)
4121  targettag, targettaghash,
4122  HASH_FIND, NULL);
4123  if (!target)
4124  {
4125  /* Nothing has this target locked; we're done here. */
4126  LWLockRelease(partitionLock);
4127  return;
4128  }
4129 
4130  /*
4131  * Each lock for an overlapping transaction represents a conflict: a
4132  * rw-dependency in to this transaction.
4133  */
4134  predlock = (PREDICATELOCK *)
4135  SHMQueueNext(&(target->predicateLocks),
4136  &(target->predicateLocks),
4137  offsetof(PREDICATELOCK, targetLink));
4138  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4139  while (predlock)
4140  {
4141  SHM_QUEUE *predlocktargetlink;
4142  PREDICATELOCK *nextpredlock;
4143  SERIALIZABLEXACT *sxact;
4144 
4145  predlocktargetlink = &(predlock->targetLink);
4146  nextpredlock = (PREDICATELOCK *)
4147  SHMQueueNext(&(target->predicateLocks),
4148  predlocktargetlink,
4149  offsetof(PREDICATELOCK, targetLink));
4150 
4151  sxact = predlock->tag.myXact;
4152  if (sxact == MySerializableXact)
4153  {
4154  /*
4155  * If we're getting a write lock on a tuple, we don't need a
4156  * predicate (SIREAD) lock on the same tuple. We can safely remove
4157  * our SIREAD lock, but we'll defer doing so until after the loop
4158  * because that requires upgrading to an exclusive partition lock.
4159  *
4160  * We can't use this optimization within a subtransaction because
4161  * the subtransaction could roll back, and we would be left
4162  * without any lock at the top level.
4163  */
4164  if (!IsSubTransaction()
4165  && GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
4166  {
4167  mypredlock = predlock;
4168  mypredlocktag = predlock->tag;
4169  }
4170  }
4171  else if (!SxactIsDoomed(sxact)
4172  && (!SxactIsCommitted(sxact)
4174  sxact->finishedBefore))
4176  {
4177  LWLockRelease(SerializableXactHashLock);
4178  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4179 
4180  /*
4181  * Re-check after getting exclusive lock because the other
4182  * transaction may have flagged a conflict.
4183  */
4184  if (!SxactIsDoomed(sxact)
4185  && (!SxactIsCommitted(sxact)
4187  sxact->finishedBefore))
4189  {
4191  }
4192 
4193  LWLockRelease(SerializableXactHashLock);
4194  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4195  }
4196 
4197  predlock = nextpredlock;
4198  }
4199  LWLockRelease(SerializableXactHashLock);
4200  LWLockRelease(partitionLock);
4201 
4202  /*
4203  * If we found one of our own SIREAD locks to remove, remove it now.
4204  *
4205  * At this point our transaction already has an ExclusiveRowLock on the
4206  * relation, so we are OK to drop the predicate lock on the tuple, if
4207  * found, without fearing that another write against the tuple will occur
4208  * before the MVCC information makes it to the buffer.
4209  */
4210  if (mypredlock != NULL)
4211  {
4212  uint32 predlockhashcode;
4213  PREDICATELOCK *rmpredlock;
4214 
4215  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
4216  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4217  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4218 
4219  /*
4220  * Remove the predicate lock from shared memory, if it wasn't removed
4221  * while the locks were released. One way that could happen is from
4222  * autovacuum cleaning up an index.
4223  */
4224  predlockhashcode = PredicateLockHashCodeFromTargetHashCode
4225  (&mypredlocktag, targettaghash);
4226  rmpredlock = (PREDICATELOCK *)
4228  &mypredlocktag,
4229  predlockhashcode,
4230  HASH_FIND, NULL);
4231  if (rmpredlock != NULL)
4232  {
4233  Assert(rmpredlock == mypredlock);
4234 
4235  SHMQueueDelete(&(mypredlock->targetLink));
4236  SHMQueueDelete(&(mypredlock->xactLink));
4237 
4238  rmpredlock = (PREDICATELOCK *)
4240  &mypredlocktag,
4241  predlockhashcode,
4242  HASH_REMOVE, NULL);
4243  Assert(rmpredlock == mypredlock);
4244 
4245  RemoveTargetIfNoLongerUsed(target, targettaghash);
4246  }
4247 
4248  LWLockRelease(SerializableXactHashLock);
4249  LWLockRelease(partitionLock);
4250  LWLockRelease(SerializablePredicateLockListLock);
4251 
4252  if (rmpredlock != NULL)
4253  {
4254  /*
4255  * Remove entry in local lock table if it exists. It's OK if it
4256  * doesn't exist; that means the lock was transferred to a new
4257  * target by a different backend.
4258  */
4260  targettag, targettaghash,
4261  HASH_REMOVE, NULL);
4262 
4263  DecrementParentLocks(targettag);
4264  }
4265  }
4266 }
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:409
TransactionId finishedBefore
Definition: lwlock.h:32
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:635
static HTAB * PredicateLockTargetHash
Definition: predicate.c:385
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4456
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2058
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:247
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define SxactIsDoomed(sxact)
Definition: predicate.c:269
#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag)
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:304
static HTAB * PredicateLockHash
Definition: predicate.c:386
#define InvalidSerializableXact
unsigned int uint32
Definition: c.h:325
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2270
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:291
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:699
static HTAB * LocalPredicateLockHash
Definition: predicate.c:402
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
bool IsSubTransaction(void)
Definition: xact.c:4495
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
SERIALIZABLEXACT * myXact
#define SxactIsCommitted(sxact)
Definition: predicate.c:266
#define offsetof(type, field)
Definition: c.h:622

◆ ClearOldPredicateLocks()

static void ClearOldPredicateLocks ( void  )
static

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

3541 {
3542  SERIALIZABLEXACT *finishedSxact;
3543  PREDICATELOCK *predlock;
3544 
3545  /*
3546  * Loop through finished transactions. They are in commit order, so we can
3547  * stop as soon as we find one that's still interesting.
3548  */
3549  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3550  finishedSxact = (SERIALIZABLEXACT *)
3553  offsetof(SERIALIZABLEXACT, finishedLink));
3554  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3555  while (finishedSxact)
3556  {
3557  SERIALIZABLEXACT *nextSxact;
3558 
3559  nextSxact = (SERIALIZABLEXACT *)
3561  &(finishedSxact->finishedLink),
3562  offsetof(SERIALIZABLEXACT, finishedLink));
3566  {
3567  /*
3568  * This transaction committed before any in-progress transaction
3569  * took its snapshot. It's no longer interesting.
3570  */
3571  LWLockRelease(SerializableXactHashLock);
3572  SHMQueueDelete(&(finishedSxact->finishedLink));
3573  ReleaseOneSerializableXact(finishedSxact, false, false);
3574  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3575  }
3576  else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3577  && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3578  {
3579  /*
3580  * Any active transactions that took their snapshot before this
3581  * transaction committed are read-only, so we can clear part of
3582  * its state.
3583  */
3584  LWLockRelease(SerializableXactHashLock);
3585 
3586  if (SxactIsReadOnly(finishedSxact))
3587  {
3588  /* A read-only transaction can be removed entirely */
3589  SHMQueueDelete(&(finishedSxact->finishedLink));
3590  ReleaseOneSerializableXact(finishedSxact, false, false);
3591  }
3592  else
3593  {
3594  /*
3595  * A read-write transaction can only be partially cleared. We
3596  * need to keep the SERIALIZABLEXACT but can release the
3597  * SIREAD locks and conflicts in.
3598  */
3599  ReleaseOneSerializableXact(finishedSxact, true, false);
3600  }
3601 
3603  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3604  }
3605  else
3606  {
3607  /* Still interesting. */
3608  break;
3609  }
3610  finishedSxact = nextSxact;
3611  }
3612  LWLockRelease(SerializableXactHashLock);
3613 
3614  /*
3615  * Loop through predicate locks on dummy transaction for summarized data.
3616  */
3617  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
3618  predlock = (PREDICATELOCK *)
3621  offsetof(PREDICATELOCK, xactLink));
3622  while (predlock)
3623  {
3624  PREDICATELOCK *nextpredlock;
3625  bool canDoPartialCleanup;
3626 
3627  nextpredlock = (PREDICATELOCK *)
3629  &predlock->xactLink,
3630  offsetof(PREDICATELOCK, xactLink));
3631 
3632  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3633  Assert(predlock->commitSeqNo != 0);
3635  canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
3636  LWLockRelease(SerializableXactHashLock);
3637 
3638  /*
3639  * If this lock originally belonged to an old enough transaction, we
3640  * can release it.
3641  */
3642  if (canDoPartialCleanup)
3643  {
3644  PREDICATELOCKTAG tag;
3645  PREDICATELOCKTARGET *target;
3646  PREDICATELOCKTARGETTAG targettag;
3647  uint32 targettaghash;
3648  LWLock *partitionLock;
3649 
3650  tag = predlock->tag;
3651  target = tag.myTarget;
3652  targettag = target->tag;
3653  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3654  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3655 
3656  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3657 
3658  SHMQueueDelete(&(predlock->targetLink));
3659  SHMQueueDelete(&(predlock->xactLink));
3660 
3663  targettaghash),
3664  HASH_REMOVE, NULL);
3665  RemoveTargetIfNoLongerUsed(target, targettaghash);
3666 
3667  LWLockRelease(partitionLock);
3668  }
3669 
3670  predlock = nextpredlock;
3671  }
3672 
3673  LWLockRelease(SerializablePredicateLockListLock);
3674  LWLockRelease(SerializableFinishedListLock);
3675 }
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:270
TransactionId finishedBefore
Definition: lwlock.h:32
static PredXactList PredXact
Definition: predicate.c:372
TransactionId SxactGlobalXmin
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2058
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:247
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:304
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
static HTAB * PredicateLockHash
Definition: predicate.c:386
unsigned int uint32
Definition: c.h:325
#define InvalidSerCommitSeqNo
SerCommitSeqNo commitSeqNo
SerCommitSeqNo HavePartialClearedThrough
PREDICATELOCKTAG tag
SerCommitSeqNo CanPartialClearThrough
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:291
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:3697
#define Assert(condition)
Definition: c.h:699
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:350
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static SHM_QUEUE * FinishedSerializableTransactions
Definition: predicate.c:387
#define offsetof(type, field)
Definition: c.h:622
PREDICATELOCKTARGET * myTarget

◆ CoarserLockCovers()

static bool CoarserLockCovers ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 1986 of file predicate.c.

References GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

1987 {
1988  PREDICATELOCKTARGETTAG targettag,
1989  parenttag;
1990 
1991  targettag = *newtargettag;
1992 
1993  /* check parents iteratively until no more */
1994  while (GetParentPredicateLockTag(&targettag, &parenttag))
1995  {
1996  targettag = parenttag;
1997  if (PredicateLockExists(&targettag))
1998  return true;
1999  }
2000 
2001  /* no more parents to check; lock is not covered */
2002  return false;
2003 }
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:1920
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:1947

◆ CreatePredicateLock()

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

Definition at line 2332 of file predicate.c.

References PREDICATELOCK::commitSeqNo, ereport, errcode(), errhint(), errmsg(), ERROR, HASH_ENTER_NULL, hash_search_with_hash_value(), InvalidSerCommitSeqNo, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, SHMQueueInit(), SHMQueueInsertBefore(), PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by predicatelock_twophase_recover(), and PredicateLockAcquire().

2335 {
2336  PREDICATELOCKTARGET *target;
2337  PREDICATELOCKTAG locktag;
2338  PREDICATELOCK *lock;
2339  LWLock *partitionLock;
2340  bool found;
2341 
2342  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2343 
2344  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
2345  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2346 
2347  /* Make sure that the target is represented. */
2348  target = (PREDICATELOCKTARGET *)
2350  targettag, targettaghash,
2351  HASH_ENTER_NULL, &found);
2352  if (!target)
2353  ereport(ERROR,
2354  (errcode(ERRCODE_OUT_OF_MEMORY),
2355  errmsg("out of shared memory"),
2356  errhint("You might need to increase max_pred_locks_per_transaction.")));
2357  if (!found)
2358  SHMQueueInit(&(target->predicateLocks));
2359 
2360  /* We've got the sxact and target, make sure they're joined. */
2361  locktag.myTarget = target;
2362  locktag.myXact = sxact;
2363  lock = (PREDICATELOCK *)
2365  PredicateLockHashCodeFromTargetHashCode(&locktag, targettaghash),
2366  HASH_ENTER_NULL, &found);
2367  if (!lock)
2368  ereport(ERROR,
2369  (errcode(ERRCODE_OUT_OF_MEMORY),
2370  errmsg("out of shared memory"),
2371  errhint("You might need to increase max_pred_locks_per_transaction.")));
2372 
2373  if (!found)
2374  {
2375  SHMQueueInsertBefore(&(target->predicateLocks), &(lock->targetLink));
2377  &(lock->xactLink));
2379  }
2380 
2381  LWLockRelease(partitionLock);
2382  LWLockRelease(SerializablePredicateLockListLock);
2383 }
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:385
int errhint(const char *fmt,...)
Definition: elog.c:987
int errcode(int sqlerrcode)
Definition: elog.c:575
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:247
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:304
#define ERROR
Definition: elog.h:43
static HTAB * PredicateLockHash
Definition: predicate.c:386
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvalidSerCommitSeqNo
SerCommitSeqNo commitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
int errmsg(const char *fmt,...)
Definition: elog.c:797
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
SERIALIZABLEXACT * myXact
PREDICATELOCKTARGET * myTarget

◆ CreatePredXact()

static SERIALIZABLEXACT * CreatePredXact ( void  )
static

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

563 {
564  PredXactListElement ptle;
565 
566  ptle = (PredXactListElement)
570  if (!ptle)
571  return NULL;
572 
573  SHMQueueDelete(&ptle->link);
575  return &ptle->sxact;
576 }
static PredXactList PredXact
Definition: predicate.c:372
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:622

◆ DecrementParentLocks()

static void DecrementParentLocks ( const PREDICATELOCKTARGETTAG targettag)
static

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

2271 {
2272  PREDICATELOCKTARGETTAG parenttag,
2273  nexttag;
2274 
2275  parenttag = *targettag;
2276 
2277  while (GetParentPredicateLockTag(&parenttag, &nexttag))
2278  {
2279  uint32 targettaghash;
2280  LOCALPREDICATELOCK *parentlock,
2281  *rmlock PG_USED_FOR_ASSERTS_ONLY;
2282 
2283  parenttag = nexttag;
2284  targettaghash = PredicateLockTargetTagHashCode(&parenttag);
2285  parentlock = (LOCALPREDICATELOCK *)
2287  &parenttag, targettaghash,
2288  HASH_FIND, NULL);
2289 
2290  /*
2291  * There's a small chance the parent lock doesn't exist in the lock
2292  * table. This can happen if we prematurely removed it because an
2293  * index split caused the child refcount to be off.
2294  */
2295  if (parentlock == NULL)
2296  continue;
2297 
2298  parentlock->childLocks--;
2299 
2300  /*
2301  * Under similar circumstances the parent lock's refcount might be
2302  * zero. This only happens if we're holding that lock (otherwise we
2303  * would have removed the entry).
2304  */
2305  if (parentlock->childLocks < 0)
2306  {
2307  Assert(parentlock->held);
2308  parentlock->childLocks = 0;
2309  }
2310 
2311  if ((parentlock->childLocks == 0) && (!parentlock->held))
2312  {
2313  rmlock = (LOCALPREDICATELOCK *)
2315  &parenttag, targettaghash,
2316  HASH_REMOVE, NULL);
2317  Assert(rmlock == parentlock);
2318  }
2319  }
2320 }
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:325
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:291
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:1947
#define Assert(condition)
Definition: c.h:699
static HTAB * LocalPredicateLockHash
Definition: predicate.c:402
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:123

◆ DeleteChildTargetLocks()

static void DeleteChildTargetLocks ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2087 of file predicate.c.

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

Referenced by PredicateLockAcquire().

2088 {
2089  SERIALIZABLEXACT *sxact;
2090  PREDICATELOCK *predlock;
2091 
2092  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
2093  sxact = MySerializableXact;
2094  predlock = (PREDICATELOCK *)
2095  SHMQueueNext(&(sxact->predicateLocks),
2096  &(sxact->predicateLocks),
2097  offsetof(PREDICATELOCK, xactLink));
2098  while (predlock)
2099  {
2100  SHM_QUEUE *predlocksxactlink;
2101  PREDICATELOCK *nextpredlock;
2102  PREDICATELOCKTAG oldlocktag;
2103  PREDICATELOCKTARGET *oldtarget;
2104  PREDICATELOCKTARGETTAG oldtargettag;
2105 
2106  predlocksxactlink = &(predlock->xactLink);
2107  nextpredlock = (PREDICATELOCK *)
2108  SHMQueueNext(&(sxact->predicateLocks),
2109  predlocksxactlink,
2110  offsetof(PREDICATELOCK, xactLink));
2111 
2112  oldlocktag = predlock->tag;
2113  Assert(oldlocktag.myXact == sxact);
2114  oldtarget = oldlocktag.myTarget;
2115  oldtargettag = oldtarget->tag;
2116 
2117  if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
2118  {
2119  uint32 oldtargettaghash;
2120  LWLock *partitionLock;
2122 
2123  oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2124  partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2125 
2126  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2127 
2128  SHMQueueDelete(predlocksxactlink);
2129  SHMQueueDelete(&(predlock->targetLink));
2130  rmpredlock = hash_search_with_hash_value
2132  &oldlocktag,
2134  oldtargettaghash),
2135  HASH_REMOVE, NULL);
2136  Assert(rmpredlock == predlock);
2137 
2138  RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2139 
2140  LWLockRelease(partitionLock);
2141 
2142  DecrementParentLocks(&oldtargettag);
2143  }
2144 
2145  predlock = nextpredlock;
2146  }
2147  LWLockRelease(SerializablePredicateLockListLock);
2148 }
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:409
Definition: lwlock.h:32
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2058
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:247
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:304
static HTAB * PredicateLockHash
Definition: predicate.c:386
unsigned int uint32
Definition: c.h:325
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2270
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:291
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:699
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
#define TargetTagIsCoveredBy(covered_target, covering_target)
Definition: predicate.c:222
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:622
PREDICATELOCKTARGET * myTarget

◆ DeleteLockTarget()

static void DeleteLockTarget ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

Definition at line 2562 of file predicate.c.

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

Referenced by TransferPredicateLocksToNewTarget().

2563 {
2564  PREDICATELOCK *predlock;
2565  SHM_QUEUE *predlocktargetlink;
2566  PREDICATELOCK *nextpredlock;
2567  bool found;
2568 
2569  Assert(LWLockHeldByMe(SerializablePredicateLockListLock));
2571 
2572  predlock = (PREDICATELOCK *)
2573  SHMQueueNext(&(target->predicateLocks),
2574  &(target->predicateLocks),
2575  offsetof(PREDICATELOCK, targetLink));
2576  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2577  while (predlock)
2578  {
2579  predlocktargetlink = &(predlock->targetLink);
2580  nextpredlock = (PREDICATELOCK *)
2581  SHMQueueNext(&(target->predicateLocks),
2582  predlocktargetlink,
2583  offsetof(PREDICATELOCK, targetLink));
2584 
2585  SHMQueueDelete(&(predlock->xactLink));
2586  SHMQueueDelete(&(predlock->targetLink));
2587 
2590  &predlock->tag,
2592  targettaghash),
2593  HASH_REMOVE, &found);
2594  Assert(found);
2595 
2596  predlock = nextpredlock;
2597  }
2598  LWLockRelease(SerializableXactHashLock);
2599 
2600  /* Remove the target itself, if possible. */
2601  RemoveTargetIfNoLongerUsed(target, targettaghash);
2602 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1841
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2058
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:247
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:304
static HTAB * PredicateLockHash
Definition: predicate.c:386
PREDICATELOCKTAG tag
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:699
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
#define offsetof(type, field)
Definition: c.h:622

◆ DropAllPredicateLocksFromTable()

static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
)
static

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

2849 {
2850  HASH_SEQ_STATUS seqstat;
2851  PREDICATELOCKTARGET *oldtarget;
2852  PREDICATELOCKTARGET *heaptarget;
2853  Oid dbId;
2854  Oid relId;
2855  Oid heapId;
2856  int i;
2857  bool isIndex;
2858  bool found;
2859  uint32 heaptargettaghash;
2860 
2861  /*
2862  * Bail out quickly if there are no serializable transactions running.
2863  * It's safe to check this without taking locks because the caller is
2864  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
2865  * would matter here can be acquired while that is held.
2866  */
2868  return;
2869 
2870  if (!PredicateLockingNeededForRelation(relation))
2871  return;
2872 
2873  dbId = relation->rd_node.dbNode;
2874  relId = relation->rd_id;
2875  if (relation->rd_index == NULL)
2876  {
2877  isIndex = false;
2878  heapId = relId;
2879  }
2880  else
2881  {
2882  isIndex = true;
2883  heapId = relation->rd_index->indrelid;
2884  }
2885  Assert(heapId != InvalidOid);
2886  Assert(transfer || !isIndex); /* index OID only makes sense with
2887  * transfer */
2888 
2889  /* Retrieve first time needed, then keep. */
2890  heaptargettaghash = 0;
2891  heaptarget = NULL;
2892 
2893  /* Acquire locks on all lock partitions */
2894  LWLockAcquire(SerializablePredicateLockListLock, LW_EXCLUSIVE);
2895  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
2897  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2898 
2899  /*
2900  * Remove the dummy entry to give us scratch space, so we know we'll be
2901  * able to create the new lock target.
2902  */
2903  if (transfer)
2904  RemoveScratchTarget(true);
2905 
2906  /* Scan through target map */
2908 
2909  while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
2910  {
2911  PREDICATELOCK *oldpredlock;
2912 
2913  /*
2914  * Check whether this is a target which needs attention.
2915  */
2916  if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) != relId)
2917  continue; /* wrong relation id */
2918  if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
2919  continue; /* wrong database id */
2920  if (transfer && !isIndex
2922  continue; /* already the right lock */
2923 
2924  /*
2925  * If we made it here, we have work to do. We make sure the heap
2926  * relation lock exists, then we walk the list of predicate locks for
2927  * the old target we found, moving all locks to the heap relation lock
2928  * -- unless they already hold that.
2929  */
2930 
2931  /*
2932  * First make sure we have the heap relation target. We only need to
2933  * do this once.
2934  */
2935  if (transfer && heaptarget == NULL)
2936  {
2937  PREDICATELOCKTARGETTAG heaptargettag;
2938 
2939  SET_PREDICATELOCKTARGETTAG_RELATION(heaptargettag, dbId, heapId);
2940  heaptargettaghash = PredicateLockTargetTagHashCode(&heaptargettag);
2942  &heaptargettag,
2943  heaptargettaghash,
2944  HASH_ENTER, &found);
2945  if (!found)
2946  SHMQueueInit(&heaptarget->predicateLocks);
2947  }
2948 
2949  /*
2950  * Loop through all the locks on the old target, replacing them with
2951  * locks on the new target.
2952  */
2953  oldpredlock = (PREDICATELOCK *)
2954  SHMQueueNext(&(oldtarget->predicateLocks),
2955  &(oldtarget->predicateLocks),
2956  offsetof(PREDICATELOCK, targetLink));
2957  while (oldpredlock)
2958  {
2959  PREDICATELOCK *nextpredlock;
2960  PREDICATELOCK *newpredlock;
2961  SerCommitSeqNo oldCommitSeqNo;
2962  SERIALIZABLEXACT *oldXact;
2963 
2964  nextpredlock = (PREDICATELOCK *)
2965  SHMQueueNext(&(oldtarget->predicateLocks),
2966  &(oldpredlock->targetLink),
2967  offsetof(PREDICATELOCK, targetLink));
2968 
2969  /*
2970  * Remove the old lock first. This avoids the chance of running
2971  * out of lock structure entries for the hash table.
2972  */
2973  oldCommitSeqNo = oldpredlock->commitSeqNo;
2974  oldXact = oldpredlock->tag.myXact;
2975 
2976  SHMQueueDelete(&(oldpredlock->xactLink));
2977 
2978  /*
2979  * No need for retail delete from oldtarget list, we're removing
2980  * the whole target anyway.
2981  */
2983  &oldpredlock->tag,
2984  HASH_REMOVE, &found);
2985  Assert(found);
2986 
2987  if (transfer)
2988  {
2989  PREDICATELOCKTAG newpredlocktag;
2990 
2991  newpredlocktag.myTarget = heaptarget;
2992  newpredlocktag.myXact = oldXact;
2993  newpredlock = (PREDICATELOCK *)
2995  &newpredlocktag,
2997  heaptargettaghash),
2998  HASH_ENTER,
2999  &found);
3000  if (!found)
3001  {
3002  SHMQueueInsertBefore(&(heaptarget->predicateLocks),
3003  &(newpredlock->targetLink));
3004  SHMQueueInsertBefore(&(newpredlocktag.myXact->predicateLocks),
3005  &(newpredlock->xactLink));
3006  newpredlock->commitSeqNo = oldCommitSeqNo;
3007  }
3008  else
3009  {
3010  if (newpredlock->commitSeqNo < oldCommitSeqNo)
3011  newpredlock->commitSeqNo = oldCommitSeqNo;
3012  }
3013 
3014  Assert(newpredlock->commitSeqNo != 0);
3015  Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
3016  || (newpredlock->tag.myXact == OldCommittedSxact));
3017  }
3018 
3019  oldpredlock = nextpredlock;
3020  }
3021 
3023  &found);
3024  Assert(found);
3025  }
3026 
3027  /* Put the scratch entry back */
3028  if (transfer)
3029  RestoreScratchTarget(true);
3030 
3031  /* Release locks in reverse order */
3032  LWLockRelease(SerializableXactHashLock);
3033  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3035  LWLockRelease(SerializablePredicateLockListLock);
3036 }
#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:477
static HTAB * PredicateLockTargetHash
Definition: predicate.c:385
static PredXactList PredXact
Definition: predicate.c:372
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:2015
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
Form_pg_index rd_index
Definition: rel.h:131
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:304
static HTAB * PredicateLockHash
Definition: predicate.c:386
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
unsigned int uint32
Definition: c.h:325
Oid rd_id
Definition: rel.h:86
#define InvalidSerCommitSeqNo
static void RestoreScratchTarget(bool lockheld)
Definition: predicate.c:2036
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:291
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define InvalidOid
Definition: postgres_ext.h:36
PREDICATELOCKTARGETTAG tag
RelFileNode rd_node
Definition: rel.h:55
SerCommitSeqNo commitSeqNo
uint64 SerCommitSeqNo
#define Assert(condition)
Definition: c.h:699
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
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:350
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:250
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:622
PREDICATELOCKTARGET * myTarget
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:121

◆ FirstPredXact()

static SERIALIZABLEXACT * FirstPredXact ( void  )
static

Definition at line 594 of file predicate.c.

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

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

595 {
596  PredXactListElement ptle;
597 
598  ptle = (PredXactListElement)
602  if (!ptle)
603  return NULL;
604 
605  return &ptle->sxact;
606 }
static PredXactList PredXact
Definition: predicate.c:372
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:622

◆ FlagRWConflict()

static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

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

4457 {
4458  Assert(reader != writer);
4459 
4460  /* First, see if this conflict causes failure. */
4462 
4463  /* Actually do the conflict flagging. */
4464  if (reader == OldCommittedSxact)
4466  else if (writer == OldCommittedSxact)
4468  else
4469  SetRWConflict(reader, writer);
4470 }
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:668
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4491
#define Assert(condition)
Definition: c.h:699
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:350
#define SXACT_FLAG_SUMMARY_CONFLICT_IN

◆ FlagSxactUnsafe()

static void FlagSxactUnsafe ( SERIALIZABLEXACT sxact)
static

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

733 {
734  RWConflict conflict,
735  nextConflict;
736 
737  Assert(SxactIsReadOnly(sxact));
738  Assert(!SxactIsROSafe(sxact));
739 
740  sxact->flags |= SXACT_FLAG_RO_UNSAFE;
741 
742  /*
743  * We know this isn't a safe snapshot, so we can stop looking for other
744  * potential conflicts.
745  */
746  conflict = (RWConflict)
748  &sxact->possibleUnsafeConflicts,
749  offsetof(RWConflictData, inLink));
750  while (conflict)
751  {
752  nextConflict = (RWConflict)
754  &conflict->inLink,
755  offsetof(RWConflictData, inLink));
756 
757  Assert(!SxactIsReadOnly(conflict->sxactOut));
758  Assert(sxact == conflict->sxactIn);
759 
760  ReleaseRWConflict(conflict);
761 
762  conflict = nextConflict;
763  }
764 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:270
struct RWConflictData * RWConflict
static void ReleaseRWConflict(RWConflict conflict)
Definition: predicate.c:724
SERIALIZABLEXACT * sxactIn
SHM_QUEUE possibleUnsafeConflicts
#define SxactIsROSafe(sxact)
Definition: predicate.c:280
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:699
#define SXACT_FLAG_RO_UNSAFE
#define offsetof(type, field)
Definition: c.h:622
SERIALIZABLEXACT * sxactOut

◆ GetParentPredicateLockTag()

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

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

1949 {
1950  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
1951  {
1952  case PREDLOCKTAG_RELATION:
1953  /* relation locks have no parent lock */
1954  return false;
1955 
1956  case PREDLOCKTAG_PAGE:
1957  /* parent lock is relation lock */
1961 
1962  return true;
1963 
1964  case PREDLOCKTAG_TUPLE:
1965  /* parent lock is page lock */
1970  return true;
1971  }
1972 
1973  /* not reachable */
1974  Assert(false);
1975  return false;
1976 }
#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:699

◆ GetPredicateLockStatusData()

PredicateLockData* GetPredicateLockStatusData ( void  )

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

1354 {
1355  PredicateLockData *data;
1356  int i;
1357  int els,
1358  el;
1359  HASH_SEQ_STATUS seqstat;
1360  PREDICATELOCK *predlock;
1361 
1362  data = (PredicateLockData *) palloc(sizeof(PredicateLockData));
1363 
1364  /*
1365  * To ensure consistency, take simultaneous locks on all partition locks
1366  * in ascending order, then SerializableXactHashLock.
1367  */
1368  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
1370  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1371 
1372  /* Get number of locks and allocate appropriately-sized arrays. */
1374  data->nelements = els;
1375  data->locktags = (PREDICATELOCKTARGETTAG *)
1376  palloc(sizeof(PREDICATELOCKTARGETTAG) * els);
1377  data->xacts = (SERIALIZABLEXACT *)
1378  palloc(sizeof(SERIALIZABLEXACT) * els);
1379 
1380 
1381  /* Scan through PredicateLockHash and copy contents */
1382  hash_seq_init(&seqstat, PredicateLockHash);
1383 
1384  el = 0;
1385 
1386  while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
1387  {
1388  data->locktags[el] = predlock->tag.myTarget->tag;
1389  data->xacts[el] = *predlock->tag.myXact;
1390  el++;
1391  }
1392 
1393  Assert(el == els);
1394 
1395  /* Release locks in reverse order */
1396  LWLockRelease(SerializableXactHashLock);
1397  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1399 
1400  return data;
1401 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1335
SERIALIZABLEXACT * xacts
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
static HTAB * PredicateLockHash
Definition: predicate.c:386
PREDICATELOCKTARGETTAG * locktags
PREDICATELOCKTAG tag
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:699
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
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:250
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 1468 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().

1469 {
1470  Snapshot snapshot;
1471 
1473 
1474  while (true)
1475  {
1476  /*
1477  * GetSerializableTransactionSnapshotInt is going to call
1478  * GetSnapshotData, so we need to provide it the static snapshot area
1479  * our caller passed to us. The pointer returned is actually the same
1480  * one passed to it, but we avoid assuming that here.
1481  */
1482  snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
1483  NULL, InvalidPid);
1484 
1486  return snapshot; /* no concurrent r/w xacts; it's safe */
1487 
1488  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1489 
1490  /*
1491  * Wait for concurrent transactions to finish. Stop early if one of
1492  * them marked us as conflicted.
1493  */
1497  {
1498  LWLockRelease(SerializableXactHashLock);
1500  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1501  }
1503 
1505  {
1506  LWLockRelease(SerializableXactHashLock);
1507  break; /* success */
1508  }
1509 
1510  LWLockRelease(SerializableXactHashLock);
1511 
1512  /* else, need to retry... */
1513  ereport(DEBUG2,
1514  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1515  errmsg("deferrable snapshot was unsafe; trying a new one")));
1516  ReleasePredicateLocks(false);
1517  }
1518 
1519  /*
1520  * Now we have a safe snapshot, so we don't need to do any further checks.
1521  */
1523  ReleasePredicateLocks(false);
1524 
1525  return snapshot;
1526 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:409
bool XactDeferrable
Definition: xact.c:79
int errcode(int sqlerrcode)
Definition: elog.c:575
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1661
SHM_QUEUE possibleUnsafeConflicts
#define InvalidSerializableXact
#define SXACT_FLAG_DEFERRABLE_WAITING
#define DEBUG2
Definition: elog.h:24
#define SxactIsROSafe(sxact)
Definition: predicate.c:280
#define ereport(elevel, rest)
Definition: elog.h:122
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1775
bool SHMQueueEmpty(const SHM_QUEUE *queue)
Definition: shmqueue.c:180
void ReleasePredicateLocks(bool isCommit)
Definition: predicate.c:3222
bool XactReadOnly
Definition: xact.c:76
#define Assert(condition)
Definition: c.h:699
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define SxactIsROUnsafe(sxact)
Definition: predicate.c:281
#define InvalidPid
Definition: miscadmin.h:31

◆ GetSafeSnapshotBlockingPids()

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

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

1539 {
1540  int num_written = 0;
1541  SERIALIZABLEXACT *sxact;
1542 
1543  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1544 
1545  /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
1546  for (sxact = FirstPredXact(); sxact != NULL; sxact = NextPredXact(sxact))
1547  {
1548  if (sxact->pid == blocked_pid)
1549  break;
1550  }
1551 
1552  /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
1553  if (sxact != NULL && SxactIsDeferrableWaiting(sxact))
1554  {
1555  RWConflict possibleUnsafeConflict;
1556 
1557  /* Traverse the list of possible unsafe conflicts collecting PIDs. */
1558  possibleUnsafeConflict = (RWConflict)
1560  &sxact->possibleUnsafeConflicts,
1561  offsetof(RWConflictData, inLink));
1562 
1563  while (possibleUnsafeConflict != NULL && num_written < output_size)
1564  {
1565  output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
1566  possibleUnsafeConflict = (RWConflict)
1568  &possibleUnsafeConflict->inLink,
1569  offsetof(RWConflictData, inLink));
1570  }
1571  }
1572 
1573  LWLockRelease(SerializableXactHashLock);
1574 
1575  return num_written;
1576 }
static void output(uint64 loop_count)
struct RWConflictData * RWConflict
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
SHM_QUEUE possibleUnsafeConflicts
static SERIALIZABLEXACT * NextPredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:609
static SERIALIZABLEXACT * FirstPredXact(void)
Definition: predicate.c:594
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define SxactIsDeferrableWaiting(sxact)
Definition: predicate.c:279
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
#define offsetof(type, field)
Definition: c.h:622
SERIALIZABLEXACT * sxactOut

◆ GetSerializableTransactionSnapshot()

Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot)

Definition at line 1590 of file predicate.c.

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

Referenced by GetTransactionSnapshot().

1591 {
1593 
1594  /*
1595  * Can't use serializable mode while recovery is still active, as it is,
1596  * for example, on a hot standby. We could get here despite the check in
1597  * check_XactIsoLevel() if default_transaction_isolation is set to
1598  * serializable, so phrase the hint accordingly.
1599  */
1600  if (RecoveryInProgress())
1601  ereport(ERROR,
1602  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1603  errmsg("cannot use serializable mode in a hot standby"),
1604  errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1605  errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1606 
1607  /*
1608  * A special optimization is available for SERIALIZABLE READ ONLY
1609  * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1610  * thereby avoid all SSI overhead once it's running.
1611  */
1613  return GetSafeSnapshot(snapshot);
1614 
1615  return GetSerializableTransactionSnapshotInt(snapshot,
1616  NULL, InvalidPid);
1617 }
bool XactDeferrable
Definition: xact.c:79
int errhint(const char *fmt,...)
Definition: elog.c:987
static Snapshot GetSafeSnapshot(Snapshot snapshot)
Definition: predicate.c:1468
int errcode(int sqlerrcode)
Definition: elog.c:575
bool RecoveryInProgress(void)
Definition: xlog.c:7949
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1661
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ereport(elevel, rest)
Definition: elog.h:122
bool XactReadOnly
Definition: xact.c:76
#define Assert(condition)
Definition: c.h:699
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define IsolationIsSerializable()
Definition: xact.h:51
#define InvalidPid
Definition: miscadmin.h:31

◆ GetSerializableTransactionSnapshotInt()

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

Definition at line 1661 of file predicate.c.

References Assert, SERIALIZABLEXACT::commitSeqNo, CreatePredXact(), elog, HASHCTL::entrysize, ereport, errcode(), errdetail(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FirstPredXact(), SERIALIZABLEXACT::flags, GET_VXID_FROM_PGPROC, GetSnapshotData(), GetTopTransactionIdIfAny(), HASH_BLOBS, hash_create(), HASH_ELEM, SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, InvalidSerializableXact, InvalidTransactionId, IsInParallelMode(), HASHCTL::keysize, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), max_predicate_locks_per_xact, max_prepared_xacts, MaxBackends, MemSet, 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, SnapshotData::xmin, and SERIALIZABLEXACT::xmin.

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

1664 {
1665  PGPROC *proc;
1666  VirtualTransactionId vxid;
1667  SERIALIZABLEXACT *sxact,
1668  *othersxact;
1669  HASHCTL hash_ctl;
1670 
1671  /* We only do this for serializable transactions. Once. */
1673 
1675 
1676  /*
1677  * Since all parts of a serializable transaction must use the same
1678  * snapshot, it is too late to establish one after a parallel operation
1679  * has begun.
1680  */
1681  if (IsInParallelMode())
1682  elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
1683 
1684  proc = MyProc;
1685  Assert(proc != NULL);
1686  GET_VXID_FROM_PGPROC(vxid, *proc);
1687 
1688  /*
1689  * First we get the sxact structure, which may involve looping and access
1690  * to the "finished" list to free a structure for use.
1691  *
1692  * We must hold SerializableXactHashLock when taking/checking the snapshot
1693  * to avoid race conditions, for much the same reasons that
1694  * GetSnapshotData takes the ProcArrayLock. Since we might have to
1695  * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
1696  * this means we have to create the sxact first, which is a bit annoying
1697  * (in particular, an elog(ERROR) in procarray.c would cause us to leak
1698  * the sxact). Consider refactoring to avoid this.
1699  */
1700 #ifdef TEST_OLDSERXID
1702 #endif
1703  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1704  do
1705  {
1706  sxact = CreatePredXact();
1707  /* If null, push out committed sxact to SLRU summary & retry. */
1708  if (!sxact)
1709  {
1710  LWLockRelease(SerializableXactHashLock);
1712  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1713  }
1714  } while (!sxact);
1715 
1716  /* Get the snapshot, or check that it's safe to use */
1717  if (!sourcevxid)
1718  snapshot = GetSnapshotData(snapshot);
1719  else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid))
1720  {
1721  ReleasePredXact(sxact);
1722  LWLockRelease(SerializableXactHashLock);
1723  ereport(ERROR,
1724  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1725  errmsg("could not import the requested snapshot"),
1726  errdetail("The source process with PID %d is not running anymore.",
1727  sourcepid)));
1728  }
1729 
1730  /*
1731  * If there are no serializable transactions which are not read-only, we
1732  * can "opt out" of predicate locking and conflict checking for a
1733  * read-only transaction.
1734  *
1735  * The reason this is safe is that a read-only transaction can only become
1736  * part of a dangerous structure if it overlaps a writable transaction
1737  * which in turn overlaps a writable transaction which committed before
1738  * the read-only transaction started. A new writable transaction can
1739  * overlap this one, but it can't meet the other condition of overlapping
1740  * a transaction which committed before this one started.
1741  */
1743  {
1744  ReleasePredXact(sxact);
1745  LWLockRelease(SerializableXactHashLock);
1746  return snapshot;
1747  }
1748 
1749  /* Maintain serializable global xmin info. */
1751  {
1753  PredXact->SxactGlobalXmin = snapshot->xmin;
1755  OldSerXidSetActiveSerXmin(snapshot->xmin);
1756  }
1757  else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
1758  {
1761  }
1762  else
1763  {
1765  }
1766 
1767  /* Initialize the structure. */
1768  sxact->vxid = vxid;
1772  SHMQueueInit(&(sxact->outConflicts));
1773  SHMQueueInit(&(sxact->inConflicts));
1775  sxact->topXid = GetTopTransactionIdIfAny();
1777  sxact->xmin = snapshot->xmin;
1778  sxact->pid = MyProcPid;
1779  SHMQueueInit(&(sxact->predicateLocks));
1780  SHMQueueElemInit(&(sxact->finishedLink));
1781  sxact->flags = 0;
1782  if (XactReadOnly)
1783  {
1784  sxact->flags |= SXACT_FLAG_READ_ONLY;
1785 
1786  /*
1787  * Register all concurrent r/w transactions as possible conflicts; if
1788  * all of them commit without any outgoing conflicts to earlier
1789  * transactions then this snapshot can be deemed safe (and we can run
1790  * without tracking predicate locks).
1791  */
1792  for (othersxact = FirstPredXact();
1793  othersxact != NULL;
1794  othersxact = NextPredXact(othersxact))
1795  {
1796  if (!SxactIsCommitted(othersxact)
1797  && !SxactIsDoomed(othersxact)
1798  && !SxactIsReadOnly(othersxact))
1799  {
1800  SetPossibleUnsafeConflict(sxact, othersxact);
1801  }
1802  }
1803  }
1804  else
1805  {
1809  }
1810 
1811  MySerializableXact = sxact;
1812  MyXactDidWrite = false; /* haven't written anything yet */
1813 
1814  LWLockRelease(SerializableXactHashLock);
1815 
1816  /* Initialize the backend-local hash table of parent locks */
1817  Assert(LocalPredicateLockHash == NULL);
1818  MemSet(&hash_ctl, 0, sizeof(hash_ctl));
1819  hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1820  hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1821  LocalPredicateLockHash = hash_create("Local predicate lock",
1823  &hash_ctl,
1824  HASH_ELEM | HASH_BLOBS);
1825 
1826  return snapshot;
1827 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:270
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:409
TransactionId finishedBefore
int MyProcPid
Definition: globals.c:42
#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
#define HASH_ELEM
Definition: hsearch.h:87
PGPROC * MyProc
Definition: proc.c:67
static PredXactList PredXact
Definition: predicate.c:372
TransactionId SxactGlobalXmin
Size entrysize
Definition: hsearch.h:73
int errcode(int sqlerrcode)
Definition: elog.c:575
#define MemSet(start, val, len)
Definition: c.h:908
bool RecoveryInProgress(void)
Definition: xlog.c:7949
int max_predicate_locks_per_xact
Definition: predicate.c:359
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define SxactIsDoomed(sxact)
Definition: predicate.c:269
bool IsInParallelMode(void)
Definition: xact.c:905
SHM_QUEUE possibleUnsafeConflicts
#define ERROR
Definition: elog.h:43
int max_prepared_xacts
Definition: twophase.c:117
#define InvalidSerializableXact
static void ReleasePredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:579
int MaxBackends
Definition: globals.c:136
struct LOCALPREDICATELOCK LOCALPREDICATELOCK
VirtualTransactionId vxid
static SERIALIZABLEXACT * NextPredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:609
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define InvalidTransactionId
Definition: transam.h:31
TransactionId xmin
Definition: snapshot.h:68
SerCommitSeqNo lastCommitBeforeSnapshot
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:404
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvalidSerCommitSeqNo
union SERIALIZABLEXACT::@110 SeqNo
static SERIALIZABLEXACT * FirstPredXact(void)
Definition: predicate.c:594
SerCommitSeqNo commitSeqNo
#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
bool XactReadOnly
Definition: xact.c:76
#define Assert(condition)
Definition: c.h:699
static void OldSerXidSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:946
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
SerCommitSeqNo prepareSeqNo
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:1509
static HTAB * LocalPredicateLockHash
Definition: predicate.c:402
SerCommitSeqNo LastSxactCommitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
void SHMQueueElemInit(SHM_QUEUE *queue)
Definition: shmqueue.c:57
int errmsg(const char *fmt,...)
Definition: elog.c:797
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
Definition: predicate.c:694
#define SXACT_FLAG_READ_ONLY
static void SummarizeOldestCommittedSxact(void)
Definition: predicate.c:1411
static bool MyXactDidWrite
Definition: predicate.c:410
#define elog
Definition: elog.h:219
#define TransactionIdIsValid(xid)
Definition: transam.h:41
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition: procarray.c:1797
Definition: proc.h:95
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:562
#define SxactIsCommitted(sxact)
Definition: predicate.c:266

◆ InitPredicateLocks()

void InitPredicateLocks ( void  )

Definition at line 1062 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, 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::predicateLocks, PredicateLockTargetTagHashCode, PredXactListDataSize, PredXactListElementDataSize, SERIALIZABLEXACT::prepareSeqNo, RWConflictDataSize, RWConflictPoolHeaderDataSize, ScratchTargetTagHash, SERIALIZABLEXACT::SeqNo, SetInvalidVirtualTransactionId, ShmemAlloc(), ShmemInitHash(), ShmemInitStruct(), SHMQueueInit(), SHMQueueInsertBefore(), SXACT_FLAG_COMMITTED, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SERIALIZABLEXACT::topXid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, and SERIALIZABLEXACT::xmin.

Referenced by CreateSharedMemoryAndSemaphores().

1063 {
1064  HASHCTL info;
1065  long max_table_size;
1066  Size requestSize;
1067  bool found;
1068 
1069 #ifndef EXEC_BACKEND
1071 #endif
1072 
1073  /*
1074  * Compute size of predicate lock target hashtable. Note these
1075  * calculations must agree with PredicateLockShmemSize!
1076  */
1077  max_table_size = NPREDICATELOCKTARGETENTS();
1078 
1079  /*
1080  * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1081  * per-predicate-lock-target information.
1082  */
1083  MemSet(&info, 0, sizeof(info));
1084  info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1085  info.entrysize = sizeof(PREDICATELOCKTARGET);
1087 
1088  PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1089  max_table_size,
1090  max_table_size,
1091  &info,
1092  HASH_ELEM | HASH_BLOBS |
1094 
1095  /*
1096  * Reserve a dummy entry in the hash table; we use it to make sure there's
1097  * always one entry available when we need to split or combine a page,
1098  * because running out of space there could mean aborting a
1099  * non-serializable transaction.
1100  */
1101  if (!IsUnderPostmaster)
1102  {
1104  HASH_ENTER, &found);
1105  Assert(!found);
1106  }
1107 
1108  /* Pre-calculate the hash and partition lock of the scratch entry */
1111 
1112  /*
1113  * Allocate hash table for PREDICATELOCK structs. This stores per
1114  * xact-lock-of-a-target information.
1115  */
1116  MemSet(&info, 0, sizeof(info));
1117  info.keysize = sizeof(PREDICATELOCKTAG);
1118  info.entrysize = sizeof(PREDICATELOCK);
1119  info.hash = predicatelock_hash;
1121 
1122  /* Assume an average of 2 xacts per target */
1123  max_table_size *= 2;
1124 
1125  PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1126  max_table_size,
1127  max_table_size,
1128  &info,
1131 
1132  /*
1133  * Compute size for serializable transaction hashtable. Note these
1134  * calculations must agree with PredicateLockShmemSize!
1135  */
1136  max_table_size = (MaxBackends + max_prepared_xacts);
1137 
1138  /*
1139  * Allocate a list to hold information on transactions participating in
1140  * predicate locking.
1141  *
1142  * Assume an average of 10 predicate locking transactions per backend.
1143  * This allows aggressive cleanup while detail is present before data must
1144  * be summarized for storage in SLRU and the "dummy" transaction.
1145  */
1146  max_table_size *= 10;
1147 
1148  PredXact = ShmemInitStruct("PredXactList",
1150  &found);
1151  Assert(found == IsUnderPostmaster);
1152  if (!found)
1153  {
1154  int i;
1155 
1164  requestSize = mul_size((Size) max_table_size,
1166  PredXact->element = ShmemAlloc(requestSize);
1167  /* Add all elements to available list, clean. */
1168  memset(PredXact->element, 0, requestSize);
1169  for (i = 0; i < max_table_size; i++)
1170  {
1172  &(PredXact->element[i].link));
1173  }
1189  }
1190  /* This never changes, so let's keep a local copy. */
1192 
1193  /*
1194  * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1195  * information for serializable transactions which have accessed data.
1196  */
1197  MemSet(&info, 0, sizeof(info));
1198  info.keysize = sizeof(SERIALIZABLEXIDTAG);
1199  info.entrysize = sizeof(SERIALIZABLEXID);
1200 
1201  SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1202  max_table_size,
1203  max_table_size,
1204  &info,
1205  HASH_ELEM | HASH_BLOBS |
1206  HASH_FIXED_SIZE);
1207 
1208  /*
1209  * Allocate space for tracking rw-conflicts in lists attached to the
1210  * transactions.
1211  *
1212  * Assume an average of 5 conflicts per transaction. Calculations suggest
1213  * that this will prevent resource exhaustion in even the most pessimal
1214  * loads up to max_connections = 200 with all 200 connections pounding the
1215  * database with serializable transactions. Beyond that, there may be
1216  * occasional transactions canceled when trying to flag conflicts. That's
1217  * probably OK.
1218  */
1219  max_table_size *= 5;
1220 
1221  RWConflictPool = ShmemInitStruct("RWConflictPool",
1223  &found);
1224  Assert(found == IsUnderPostmaster);
1225  if (!found)
1226  {
1227  int i;
1228 
1230  requestSize = mul_size((Size) max_table_size,
1232  RWConflictPool->element = ShmemAlloc(requestSize);
1233  /* Add all elements to available list, clean. */
1234  memset(RWConflictPool->element, 0, requestSize);
1235  for (i = 0; i < max_table_size; i++)
1236  {
1238  &(RWConflictPool->element[i].outLink));
1239  }
1240  }
1241 
1242  /*
1243  * Create or attach to the header for the list of finished serializable
1244  * transactions.
1245  */
1247  ShmemInitStruct("FinishedSerializableTransactions",
1248  sizeof(SHM_QUEUE),
1249  &found);
1250  Assert(found == IsUnderPostmaster);
1251  if (!found)
1253 
1254  /*
1255  * Initialize the SLRU storage for old committed serializable
1256  * transactions.
1257  */
1258  OldSerXidInit();
1259 }
TransactionId finishedBefore
#define PredXactListDataSize
struct SERIALIZABLEXID SERIALIZABLEXID
static HTAB * PredicateLockTargetHash
Definition: predicate.c:385
#define HASH_ELEM
Definition: hsearch.h:87
#define NPREDICATELOCKTARGETENTS()
Definition: predicate.c:253
static PredXactList PredXact
Definition: predicate.c:372
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:1327
static HTAB * SerializableXidHash
Definition: predicate.c:384
#define MemSet(start, val, len)
Definition: c.h:908
static void OldSerXidInit(void)
Definition: predicate.c:796
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:247
SHM_QUEUE possibleUnsafeConflicts
static HTAB * PredicateLockHash
Definition: predicate.c:386
int max_prepared_xacts
Definition: twophase.c:117
static RWConflictPoolHeader RWConflictPool
Definition: predicate.c:378
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:136
#define RWConflictDataSize
VirtualTransactionId vxid
bool IsUnderPostmaster
Definition: globals.c:110
#define InvalidTransactionId
Definition: transam.h:31
SerCommitSeqNo lastCommitBeforeSnapshot
union SERIALIZABLEXACT::@110 SeqNo
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:291
Size keysize
Definition: hsearch.h:72
#define Assert(condition)
Definition: c.h:699
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:77
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
SerCommitSeqNo prepareSeqNo
size_t Size
Definition: c.h:433
SerCommitSeqNo LastSxactCommitSeqNo
SERIALIZABLEXACT * OldCommittedSxact
#define HASH_FIXED_SIZE
Definition: hsearch.h:96
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:350
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
int i
static const PREDICATELOCKTARGETTAG ScratchTargetTag
Definition: predicate.c:394
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:387
static uint32 ScratchTargetTagHash
Definition: predicate.c:395
static LWLock * ScratchPartitionLock
Definition: predicate.c:396
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:562
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 2168 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().

2169 {
2170  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2171  {
2172  case PREDLOCKTAG_RELATION:
2177 
2178  case PREDLOCKTAG_PAGE:
2180 
2181  case PREDLOCKTAG_TUPLE:
2182 
2183  /*
2184  * not reachable: nothing is finer-granularity than a tuple, so we
2185  * should never try to promote to it.
2186  */
2187  Assert(false);
2188  return 0;
2189  }
2190 
2191  /* not reachable */
2192  Assert(false);
2193  return 0;
2194 }
int max_predicate_locks_per_xact
Definition: predicate.c:359
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define Assert(condition)
Definition: c.h:699
int max_predicate_locks_per_relation
Definition: predicate.c:360
int max_predicate_locks_per_page
Definition: predicate.c:361

◆ NextPredXact()

static SERIALIZABLEXACT * NextPredXact ( SERIALIZABLEXACT sxact)
static

Definition at line 609 of file predicate.c.

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

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

610 {
611  PredXactListElement ptle;
612 
613  Assert(ShmemAddrIsValid(sxact));
614 
615  ptle = (PredXactListElement)
616  (((char *) sxact)
619  ptle = (PredXactListElement)
621  &ptle->link,
623  if (!ptle)
624  return NULL;
625 
626  return &ptle->sxact;
627 }
static PredXactList PredXact
Definition: predicate.c:372
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:699
struct PredXactListElementData * PredXactListElement
#define offsetof(type, field)
Definition: c.h:622

◆ OldSerXidAdd()

static void OldSerXidAdd ( TransactionId  xid,
SerCommitSeqNo  minConflictCommitSeqNo 
)
static

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

835 {
836  TransactionId tailXid;
837  int targetPage;
838  int slotno;
839  int firstZeroPage;
840  bool isNewPage;
841 
843 
844  targetPage = OldSerXidPage(xid);
845 
846  LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);
847 
848  /*
849  * If no serializable transactions are active, there shouldn't be anything
850  * to push out to the SLRU. Hitting this assert would mean there's
851  * something wrong with the earlier cleanup logic.
852  */
853  tailXid = oldSerXidControl->tailXid;
854  Assert(TransactionIdIsValid(tailXid));
855 
856  /*
857  * If the SLRU is currently unused, zero out the whole active region from
858  * tailXid to headXid before taking it into use. Otherwise zero out only
859  * any new pages that enter the tailXid-headXid range as we advance
860  * headXid.
861  */
862  if (oldSerXidControl->headPage < 0)
863  {
864  firstZeroPage = OldSerXidPage(tailXid);
865  isNewPage = true;
866  }
867  else
868  {
869  firstZeroPage = OldSerXidNextPage(oldSerXidControl->headPage);
871  targetPage);
872  }
873 
876  oldSerXidControl->headXid = xid;
877  if (isNewPage)
878  oldSerXidControl->headPage = targetPage;
879 
880  if (isNewPage)
881  {
882  /* Initialize intervening pages. */
883  while (firstZeroPage != targetPage)
884  {
885  (void) SimpleLruZeroPage(OldSerXidSlruCtl, firstZeroPage);
886  firstZeroPage = OldSerXidNextPage(firstZeroPage);
887  }
888  slotno = SimpleLruZeroPage(OldSerXidSlruCtl, targetPage);
889  }
890  else
891  slotno = SimpleLruReadPage(OldSerXidSlruCtl, targetPage, true, xid);
892 
893  OldSerXidValue(slotno, xid) = minConflictCommitSeqNo;
894  OldSerXidSlruCtl->shared->page_dirty[slotno] = true;
895 
896  LWLockRelease(OldSerXidLock);
897 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:474
#define OldSerXidPage(xid)
Definition: predicate.c:331
#define OldSerXidSlruCtl
Definition: predicate.c:314
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:375
TransactionId headXid
Definition: predicate.c:336
#define Assert(condition)
Definition: c.h:699
static bool OldSerXidPagePrecedesLogically(int p, int q)
Definition: predicate.c:773
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
static OldSerXidControl oldSerXidControl
Definition: predicate.c:342
#define OldSerXidValue(slotno, xid)
Definition: predicate.c:327
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:263
#define OldSerXidNextPage(page)
Definition: predicate.c:325
TransactionId tailXid
Definition: predicate.c:337

◆ OldSerXidGetMinConflictCommitSeqNo()

static SerCommitSeqNo OldSerXidGetMinConflictCommitSeqNo ( TransactionId  xid)
static

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

906 {
907  TransactionId headXid;
908  TransactionId tailXid;
910  int slotno;
911 
913 
914  LWLockAcquire(OldSerXidLock, LW_SHARED);
915  headXid = oldSerXidControl->headXid;
916  tailXid = oldSerXidControl->tailXid;
917  LWLockRelease(OldSerXidLock);
918 
919  if (!TransactionIdIsValid(headXid))
920  return 0;
921 
922  Assert(TransactionIdIsValid(tailXid));
923 
924  if (TransactionIdPrecedes(xid, tailXid)
925  || TransactionIdFollows(xid, headXid))
926  return 0;
927 
928  /*
929  * The following function must be called without holding OldSerXidLock,
930  * but will return with that lock held, which must then be released.
931  */
933  OldSerXidPage(xid), xid);
934  val = OldSerXidValue(slotno, xid);
935  LWLockRelease(OldSerXidLock);
936  return val;
937 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:474
#define OldSerXidPage(xid)
Definition: predicate.c:331
#define OldSerXidSlruCtl
Definition: predicate.c:314
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
TransactionId headXid
Definition: predicate.c:336
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:699
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
static OldSerXidControl oldSerXidControl
Definition: predicate.c:342
#define OldSerXidValue(slotno, xid)
Definition: predicate.c:327
#define TransactionIdIsValid(xid)
Definition: transam.h:41
long val
Definition: informix.c:689
TransactionId tailXid
Definition: predicate.c:337

◆ OldSerXidInit()

static void OldSerXidInit ( void  )
static

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

797 {
798  bool found;
799 
800  /*
801  * Set up SLRU management of the pg_serial data.
802  */
804  SimpleLruInit(OldSerXidSlruCtl, "oldserxid",
805  NUM_OLDSERXID_BUFFERS, 0, OldSerXidLock, "pg_serial",
807  /* Override default assumption that writes should be fsync'd */
808  OldSerXidSlruCtl->do_fsync = false;
809 
810  /*
811  * Create or attach to the OldSerXidControl structure.
812  */
814  ShmemInitStruct("OldSerXidControlData", sizeof(OldSerXidControlData), &found);
815 
816  Assert(found == IsUnderPostmaster);
817  if (!found)
818  {
819  /*
820  * Set control information to reflect empty SLRU.
821  */
825  }
826 }
struct OldSerXidControlData * OldSerXidControl
Definition: predicate.c:340
#define NUM_OLDSERXID_BUFFERS
Definition: predicate.h:31
#define OldSerXidSlruCtl
Definition: predicate.c:314
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
bool IsUnderPostmaster
Definition: globals.c:110
#define InvalidTransactionId
Definition: transam.h:31
TransactionId headXid
Definition: predicate.c:336
#define Assert(condition)
Definition: c.h:699
static bool OldSerXidPagePrecedesLogically(int p, int q)
Definition: predicate.c:773
static OldSerXidControl oldSerXidControl
Definition: predicate.c:342
TransactionId tailXid
Definition: predicate.c:337
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 773 of file predicate.c.

References Assert, and OLDSERXID_MAX_PAGE.

Referenced by OldSerXidAdd(), and OldSerXidInit().

774 {
775  int diff;
776 
777  /*
778  * We have to compare modulo (OLDSERXID_MAX_PAGE+1)/2. Both inputs should
779  * be in the range 0..OLDSERXID_MAX_PAGE.
780  */
781  Assert(p >= 0 && p <= OLDSERXID_MAX_PAGE);
782  Assert(q >= 0 && q <= OLDSERXID_MAX_PAGE);
783 
784  diff = p - q;
785  if (diff >= ((OLDSERXID_MAX_PAGE + 1) / 2))
786  diff -= OLDSERXID_MAX_PAGE + 1;
787  else if (diff < -((int) (OLDSERXID_MAX_PAGE + 1) / 2))
788  diff += OLDSERXID_MAX_PAGE + 1;
789  return diff < 0;
790 }
#define OLDSERXID_MAX_PAGE
Definition: predicate.c:323
#define Assert(condition)
Definition: c.h:699

◆ OldSerXidSetActiveSerXmin()

static void OldSerXidSetActiveSerXmin ( TransactionId  xid)
static

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

947 {
948  LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);
949 
950  /*
951  * When no sxacts are active, nothing overlaps, set the xid values to
952  * invalid to show that there are no valid entries. Don't clear headPage,
953  * though. A new xmin might still land on that page, and we don't want to
954  * repeatedly zero out the same page.
955  */
956  if (!TransactionIdIsValid(xid))
957  {
960  LWLockRelease(OldSerXidLock);
961  return;
962  }
963 
964  /*
965  * When we're recovering prepared transactions, the global xmin might move
966  * backwards depending on the order they're recovered. Normally that's not
967  * OK, but during recovery no serializable transactions will commit, so
968  * the SLRU is empty and we can get away with it.
969  */
970  if (RecoveryInProgress())
971  {
975  {
976  oldSerXidControl->tailXid = xid;
977  }
978  LWLockRelease(OldSerXidLock);
979  return;
980  }
981 
984 
985  oldSerXidControl->tailXid = xid;
986 
987  LWLockRelease(OldSerXidLock);
988 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
bool RecoveryInProgress(void)
Definition: xlog.c:7949
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define InvalidTransactionId
Definition: transam.h:31
TransactionId headXid
Definition: predicate.c:336
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define Assert(condition)
Definition: c.h:699
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
static OldSerXidControl oldSerXidControl
Definition: predicate.c:342
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId tailXid
Definition: predicate.c:337

◆ OnConflict_CheckForSerializationFailure()

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

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

4493 {
4494  bool failure;
4495  RWConflict conflict;
4496 
4497  Assert(LWLockHeldByMe(SerializableXactHashLock));
4498 
4499  failure = false;
4500 
4501  /*------------------------------------------------------------------------
4502  * Check for already-committed writer with rw-conflict out flagged
4503  * (conflict-flag on W means that T2 committed before W):
4504  *
4505  * R ------> W ------> T2
4506  * rw rw
4507  *
4508  * That is a dangerous structure, so we must abort. (Since the writer
4509  * has already committed, we must be the reader)
4510  *------------------------------------------------------------------------
4511  */
4512  if (SxactIsCommitted(writer)
4513  && (SxactHasConflictOut(writer) || SxactHasSummaryConflictOut(writer)))
4514  failure = true;
4515 
4516  /*------------------------------------------------------------------------
4517  * Check whether the writer has become a pivot with an out-conflict
4518  * committed transaction (T2), and T2 committed first:
4519  *
4520  * R ------> W ------> T2
4521  * rw rw
4522  *
4523  * Because T2 must've committed first, there is no anomaly if:
4524  * - the reader committed before T2
4525  * - the writer committed before T2
4526  * - the reader is a READ ONLY transaction and the reader was concurrent
4527  * with T2 (= reader acquired its snapshot before T2 committed)
4528  *
4529  * We also handle the case that T2 is prepared but not yet committed
4530  * here. In that case T2 has already checked for conflicts, so if it
4531  * commits first, making the above conflict real, it's too late for it
4532  * to abort.
4533  *------------------------------------------------------------------------
4534  */
4535  if (!failure)
4536  {
4537  if (SxactHasSummaryConflictOut(writer))
4538  {
4539  failure = true;
4540  conflict = NULL;
4541  }
4542  else
4543  conflict = (RWConflict)
4544  SHMQueueNext(&writer->outConflicts,
4545  &writer->outConflicts,
4546  offsetof(RWConflictData, outLink));
4547  while (conflict)
4548  {
4549  SERIALIZABLEXACT *t2 = conflict->sxactIn;
4550 
4551  if (SxactIsPrepared(t2)
4552  && (!SxactIsCommitted(reader)
4553  || t2->prepareSeqNo <= reader->commitSeqNo)
4554  && (!SxactIsCommitted(writer)
4555  || t2->prepareSeqNo <= writer->commitSeqNo)
4556  && (!SxactIsReadOnly(reader)
4557  || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
4558  {
4559  failure = true;
4560  break;
4561  }
4562  conflict = (RWConflict)
4563  SHMQueueNext(&writer->outConflicts,
4564  &conflict->outLink,
4565  offsetof(RWConflictData, outLink));
4566  }
4567  }
4568 
4569  /*------------------------------------------------------------------------
4570  * Check whether the reader has become a pivot with a writer
4571  * that's committed (or prepared):
4572  *
4573  * T0 ------> R ------> W
4574  * rw rw
4575  *
4576  * Because W must've committed first for an anomaly to occur, there is no
4577  * anomaly if:
4578  * - T0 committed before the writer
4579  * - T0 is READ ONLY, and overlaps the writer
4580  *------------------------------------------------------------------------
4581  */
4582  if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
4583  {
4584  if (SxactHasSummaryConflictIn(reader))
4585  {
4586  failure = true;
4587  conflict = NULL;
4588  }
4589  else
4590  conflict = (RWConflict)
4591  SHMQueueNext(&reader->inConflicts,
4592  &reader->inConflicts,
4593  offsetof(RWConflictData, inLink));
4594  while (conflict)
4595  {
4596  SERIALIZABLEXACT *t0 = conflict->sxactOut;
4597 
4598  if (!SxactIsDoomed(t0)
4599  && (!SxactIsCommitted(t0)
4600  || t0->commitSeqNo >= writer->prepareSeqNo)
4601  && (!SxactIsReadOnly(t0)
4602  || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
4603  {
4604  failure = true;
4605  break;
4606  }
4607  conflict = (RWConflict)
4608  SHMQueueNext(&reader->inConflicts,
4609  &conflict->inLink,
4610  offsetof(RWConflictData, inLink));
4611  }
4612  }
4613 
4614  if (failure)
4615  {
4616  /*
4617  * We have to kill a transaction to avoid a possible anomaly from
4618  * occurring. If the writer is us, we can just ereport() to cause a
4619  * transaction abort. Otherwise we flag the writer for termination,
4620  * causing it to abort when it tries to commit. However, if the writer
4621  * is a prepared transaction, already prepared, we can't abort it
4622  * anymore, so we have to kill the reader instead.
4623  */
4624  if (MySerializableXact == writer)
4625  {
4626  LWLockRelease(SerializableXactHashLock);
4627  ereport(ERROR,
4628  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4629  errmsg("could not serialize access due to read/write dependencies among transactions"),
4630  errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
4631  errhint("The transaction might succeed if retried.")));
4632  }
4633  else if (SxactIsPrepared(writer))
4634  {
4635  LWLockRelease(SerializableXactHashLock);
4636 
4637  /* if we're not the writer, we have to be the reader */
4638  Assert(MySerializableXact == reader);
4639  ereport(ERROR,
4640  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4641  errmsg("could not serialize access due to read/write dependencies among transactions"),
4642  errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
4643  errhint("The transaction might succeed if retried.")));
4644  }
4645  writer->flags |= SXACT_FLAG_DOOMED;
4646  }
4647 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:270
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:409
int errhint(const char *fmt,...)
Definition: elog.c:987
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:271
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1841
struct RWConflictData * RWConflict
int errcode(int sqlerrcode)
Definition: elog.c:575
#define SxactIsPrepared(sxact)
Definition: predicate.c:267
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
SERIALIZABLEXACT * sxactIn
#define SxactIsDoomed(sxact)
Definition: predicate.c:269
#define ERROR
Definition: elog.h:43
SerCommitSeqNo lastCommitBeforeSnapshot
#define ereport(elevel, rest)
Definition: elog.h:122
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:272
union SERIALIZABLEXACT::@110 SeqNo
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:278
#define Assert(condition)
Definition: c.h:699
SerCommitSeqNo prepareSeqNo
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define SxactIsCommitted(sxact)
Definition: predicate.c:266
#define offsetof(type, field)
Definition: c.h:622
SERIALIZABLEXACT * sxactOut

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

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

1884 {
1885  PREDICATELOCKTARGETTAG targettag;
1886  uint32 targettaghash;
1887  LWLock *partitionLock;
1888  PREDICATELOCKTARGET *target;
1889 
1891  relation->rd_node.dbNode,
1892  relation->rd_id,
1893  blkno);
1894 
1895  targettaghash = PredicateLockTargetTagHashCode(&targettag);
1896  partitionLock = PredicateLockHashPartitionLock(targettaghash);
1897  LWLockAcquire(partitionLock, LW_SHARED);
1898  target = (PREDICATELOCKTARGET *)
1900  &targettag, targettaghash,
1901  HASH_FIND, NULL);
1902  LWLockRelease(partitionLock);
1903 
1904  return (target != NULL);
1905 }
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:385
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:247
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
unsigned int uint32
Definition: c.h:325
Oid rd_id
Definition: rel.h:86
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:291
RelFileNode rd_node
Definition: rel.h:55
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121

◆ PostPrepare_PredicateLocks()

void PostPrepare_PredicateLocks ( TransactionId  xid)

Definition at line 4828 of file predicate.c.

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

Referenced by PrepareTransaction().

4829 {
4831  return;
4832 
4834 
4835  MySerializableXact->pid = 0;
4836 
4838  LocalPredicateLockHash = NULL;
4839 
4841  MyXactDidWrite = false;
4842 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:409
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:814
#define SxactIsPrepared(sxact)
Definition: predicate.c:267
#define InvalidSerializableXact
#define Assert(condition)
Definition: c.h:699
static HTAB * LocalPredicateLockHash
Definition: predicate.c:402
static bool MyXactDidWrite
Definition: predicate.c:410

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4666 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, SxactIsPrepared, SxactIsReadOnly, and RWConflictData::sxactOut.

Referenced by CommitTransaction(), and PrepareTransaction().

4667 {
4668  RWConflict nearConflict;
4669 
4671  return;
4672 
4674 
4675  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4676 
4677  /* Check if someone else has already decided that we need to die */
4679  {
4680  LWLockRelease(SerializableXactHashLock);
4681  ereport(ERROR,
4682  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4683  errmsg("could not serialize access due to read/write dependencies among transactions"),
4684  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4685  errhint("The transaction might succeed if retried.")));
4686  }
4687 
4688  nearConflict = (RWConflict)
4691  offsetof(RWConflictData, inLink));
4692  while (nearConflict)
4693  {
4694  if (!SxactIsCommitted(nearConflict->sxactOut)
4695  && !SxactIsDoomed(nearConflict->sxactOut))
4696  {
4697  RWConflict farConflict;
4698 
4699  farConflict = (RWConflict)
4700  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4701  &nearConflict->sxactOut->inConflicts,
4702  offsetof(RWConflictData, inLink));
4703  while (farConflict)
4704  {
4705  if (farConflict->sxactOut == MySerializableXact
4706  || (!SxactIsCommitted(farConflict->sxactOut)
4707  && !SxactIsReadOnly(farConflict->sxactOut)
4708  && !SxactIsDoomed(farConflict->sxactOut)))
4709  {
4710  /*
4711  * Normally, we kill the pivot transaction to make sure we
4712  * make progress if the failing transaction is retried.
4713  * However, we can't kill it if it's already prepared, so
4714  * in that case we commit suicide instead.
4715  */
4716  if (SxactIsPrepared(nearConflict->sxactOut))
4717  {
4718  LWLockRelease(SerializableXactHashLock);
4719  ereport(ERROR,
4720  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4721  errmsg("could not serialize access due to read/write dependencies among transactions"),
4722  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4723  errhint("The transaction might succeed if retried.")));
4724  }
4725  nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4726  break;
4727  }
4728  farConflict = (RWConflict)
4729  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4730  &farConflict->inLink,
4731  offsetof(RWConflictData, inLink));
4732  }
4733  }
4734 
4735  nearConflict = (RWConflict)
4737  &nearConflict->inLink,
4738  offsetof(RWConflictData, inLink));
4739  }
4740 
4743 
4744  LWLockRelease(SerializableXactHashLock);
4745 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:270
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:409
int errhint(const char *fmt,...)
Definition: elog.c:987
static PredXactList PredXact
Definition: predicate.c:372
struct RWConflictData * RWConflict
int errcode(int sqlerrcode)
Definition: elog.c:575
#define SxactIsPrepared(sxact)
Definition: predicate.c:267
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define SxactIsDoomed(sxact)
Definition: predicate.c:269
#define ERROR
Definition: elog.h:43
#define InvalidSerializableXact
#define SXACT_FLAG_PREPARED
#define ereport(elevel, rest)
Definition: elog.h:122
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:699
SerCommitSeqNo prepareSeqNo
SerCommitSeqNo LastSxactCommitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define IsolationIsSerializable()
Definition: xact.h:51
#define SxactIsCommitted(sxact)
Definition: predicate.c:266
#define offsetof(type, field)
Definition: c.h:622
SERIALIZABLEXACT * sxactOut

◆ predicatelock_hash()

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

Definition at line 1327 of file predicate.c.

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

Referenced by InitPredicateLocks().

1328 {
1329  const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
1330  uint32 targethash;
1331 
1332  Assert(keysize == sizeof(PREDICATELOCKTAG));
1333 
1334  /* Look into the associated target object, and compute its hash code */
1335  targethash = PredicateLockTargetTagHashCode(&predicatelocktag->myTarget->tag);
1336 
1337  return PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash);
1338 }
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:304
unsigned int uint32
Definition: c.h:325
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:291
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:699
PREDICATELOCKTARGET * myTarget

◆ predicatelock_twophase_recover()

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

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

4879 {
4880  TwoPhasePredicateRecord *record;
4881 
4882  Assert(len == sizeof(TwoPhasePredicateRecord));
4883 
4884  record = (TwoPhasePredicateRecord *) recdata;
4885 
4886  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
4887  (record->type == TWOPHASEPREDICATERECORD_LOCK));
4888 
4889  if (record->type == TWOPHASEPREDICATERECORD_XACT)
4890  {
4891  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4892  TwoPhasePredicateXactRecord *xactRecord;
4893  SERIALIZABLEXACT *sxact;
4894  SERIALIZABLEXID *sxid;
4895  SERIALIZABLEXIDTAG sxidtag;
4896  bool found;
4897 
4898  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4899 
4900  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4901  sxact = CreatePredXact();
4902  if (!sxact)
4903  ereport(ERROR,
4904  (errcode(ERRCODE_OUT_OF_MEMORY),
4905  errmsg("out of shared memory")));
4906 
4907  /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
4908  sxact->vxid.backendId = InvalidBackendId;
4910  sxact->pid = 0;
4911 
4912  /* a prepared xact hasn't committed yet */
4916 
4918 
4919  /*
4920  * Don't need to track this; no transactions running at the time the
4921  * recovered xact started are still active, except possibly other
4922  * prepared xacts and we don't care whether those are RO_SAFE or not.
4923  */
4925 
4926  SHMQueueInit(&(sxact->predicateLocks));
4927  SHMQueueElemInit(&(sxact->finishedLink));
4928 
4929  sxact->topXid = xid;
4930  sxact->xmin = xactRecord->xmin;
4931  sxact->flags = xactRecord->flags;
4932  Assert(SxactIsPrepared(sxact));
4933  if (!SxactIsReadOnly(sxact))
4934  {
4938  }
4939 
4940  /*
4941  * We don't know whether the transaction had any conflicts or not, so
4942  * we'll conservatively assume that it had both a conflict in and a
4943  * conflict out, and represent that with the summary conflict flags.
4944  */
4945  SHMQueueInit(&(sxact->outConflicts));
4946  SHMQueueInit(&(sxact->inConflicts));
4949 
4950  /* Register the transaction's xid */
4951  sxidtag.xid = xid;
4953  &sxidtag,
4954  HASH_ENTER, &found);
4955  Assert(sxid != NULL);
4956  Assert(!found);
4957  sxid->myXact = (SERIALIZABLEXACT *) sxact;
4958 
4959  /*
4960  * Update global xmin. Note that this is a special case compared to
4961  * registering a normal transaction, because the global xmin might go
4962  * backwards. That's OK, because until recovery is over we're not
4963  * going to complete any transactions or create any non-prepared
4964  * transactions, so there's no danger of throwing away.
4965  */
4968  {
4969  PredXact->SxactGlobalXmin = sxact->xmin;
4972  }
4973  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
4974  {
4977  }
4978 
4979  LWLockRelease(SerializableXactHashLock);
4980  }
4981  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
4982  {
4983  /* Lock record. Recreate the PREDICATELOCK */
4984  TwoPhasePredicateLockRecord *lockRecord;
4985  SERIALIZABLEXID *sxid;
4986  SERIALIZABLEXACT *sxact;
4987  SERIALIZABLEXIDTAG sxidtag;
4988  uint32 targettaghash;
4989 
4990  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
4991  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
4992 
4993  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4994  sxidtag.xid = xid;
4995  sxid = (SERIALIZABLEXID *)
4996  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4997  LWLockRelease(SerializableXactHashLock);
4998 
4999  Assert(sxid != NULL);
5000  sxact = sxid->myXact;
5001  Assert(sxact != InvalidSerializableXact);
5002 
5003  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5004  }
5005 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:270
TransactionId finishedBefore
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2332
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
static PredXactList PredXact
Definition: predicate.c:372
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
TransactionId SxactGlobalXmin
int errcode(int sqlerrcode)
Definition: elog.c:575
static HTAB * SerializableXidHash
Definition: predicate.c:384
SERIALIZABLEXACT * myXact
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
#define SxactIsPrepared(sxact)
Definition: predicate.c:267
TwoPhasePredicateRecordType type
LocalTransactionId localTransactionId
Definition: lock.h:66
PREDICATELOCKTARGETTAG target
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
SHM_QUEUE possibleUnsafeConflicts
#define ERROR
Definition: elog.h:43
int max_prepared_xacts
Definition: twophase.c:117
TwoPhasePredicateXactRecord xactRecord
#define InvalidSerializableXact
int MaxBackends
Definition: globals.c:136
VirtualTransactionId vxid
#define InvalidTransactionId
Definition: transam.h:31
unsigned int uint32
Definition: c.h:325
uint32 LocalTransactionId
Definition: c.h:476
SerCommitSeqNo lastCommitBeforeSnapshot
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvalidSerCommitSeqNo
union SERIALIZABLEXACT::@110 SeqNo
SerCommitSeqNo commitSeqNo
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:291
#define InvalidBackendId
Definition: backendid.h:23
#define RecoverySerCommitSeqNo
#define Assert(condition)
Definition: c.h:699
BackendId backendId
Definition: lock.h:65
static void OldSerXidSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:946
SerCommitSeqNo prepareSeqNo
union TwoPhasePredicateRecord::@111 data
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
void SHMQueueElemInit(SHM_QUEUE *queue)
Definition: shmqueue.c:57
int errmsg(const char *fmt,...)
Definition: elog.c:797
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TwoPhasePredicateLockRecord lockRecord
#define SXACT_FLAG_SUMMARY_CONFLICT_IN
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:562
Definition: