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

Go to the source code of this file.

Data Structures

struct  SerialControlData
 

Macros

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

Typedefs

typedef struct SerialControlData SerialControlData
 
typedef struct SerialControlDataSerialControl
 

Functions

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

Variables

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

Macro Definition Documentation

◆ NPREDICATELOCKTARGETENTS

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

Definition at line 259 of file predicate.c.

Referenced by InitPredicateLocks(), and PredicateLockShmemSize().

◆ PredicateLockHashCodeFromTargetHashCode

#define PredicateLockHashCodeFromTargetHashCode (   predicatelocktag,
  targethash 
)

◆ PredicateLockHashPartition

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

Definition at line 251 of file predicate.c.

◆ PredicateLockHashPartitionLock

#define PredicateLockHashPartitionLock (   hashcode)

◆ PredicateLockHashPartitionLockByIndex

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

◆ PredicateLockTargetTagHashCode

◆ SERIAL_ENTRIESPERPAGE

#define SERIAL_ENTRIESPERPAGE   (SERIAL_PAGESIZE / SERIAL_ENTRYSIZE)

Definition at line 325 of file predicate.c.

Referenced by SerialInit(), and SerialPagePrecedesLogically().

◆ SERIAL_ENTRYSIZE

#define SERIAL_ENTRYSIZE   sizeof(SerCommitSeqNo)

Definition at line 324 of file predicate.c.

◆ SERIAL_MAX_PAGE

#define SERIAL_MAX_PAGE   (MaxTransactionId / SERIAL_ENTRIESPERPAGE)

Definition at line 330 of file predicate.c.

◆ SERIAL_PAGESIZE

#define SERIAL_PAGESIZE   BLCKSZ

Definition at line 323 of file predicate.c.

◆ SerialNextPage

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

Definition at line 332 of file predicate.c.

Referenced by SerialAdd().

◆ SerialPage

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

Definition at line 338 of file predicate.c.

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

◆ SerialSlruCtl

#define SerialSlruCtl   (&SerialSlruCtlData)

◆ SerialValue

#define SerialValue (   slotno,
  xid 
)
Value:
(SerialSlruCtl->shared->page_buffer[slotno] + \
#define SerialSlruCtl
Definition: predicate.c:321
unsigned int uint32
Definition: c.h:441
uint64 SerCommitSeqNo
#define SERIAL_ENTRYSIZE
Definition: predicate.c:324
#define SERIAL_ENTRIESPERPAGE
Definition: predicate.c:325

Definition at line 334 of file predicate.c.

Referenced by SerialAdd(), and SerialGetMinConflictCommitSeqNo().

◆ SxactHasConflictOut

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

◆ SxactHasSummaryConflictIn

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

◆ SxactHasSummaryConflictOut

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

◆ SxactIsCommitted

◆ SxactIsDeferrableWaiting

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

Definition at line 285 of file predicate.c.

Referenced by GetSafeSnapshotBlockingPids(), and ReleasePredicateLocks().

◆ SxactIsDoomed

◆ SxactIsOnFinishedList

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

Definition at line 262 of file predicate.c.

Referenced by ReleaseOneSerializableXact(), and ReleasePredicateLocks().

◆ SxactIsPartiallyReleased

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

Definition at line 288 of file predicate.c.

Referenced by PreCommit_CheckForSerializationFailure(), and ReleasePredicateLocks().

◆ SxactIsPrepared

◆ SxactIsReadOnly

◆ SxactIsRolledBack

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

◆ SxactIsROSafe

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

◆ SxactIsROUnsafe

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

Definition at line 287 of file predicate.c.

Referenced by GetSafeSnapshot(), and ReleasePredicateLocks().

◆ TargetTagIsCoveredBy

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

Definition at line 228 of file predicate.c.

Referenced by DeleteChildTargetLocks().

Typedef Documentation

◆ SerialControl

Definition at line 347 of file predicate.c.

◆ SerialControlData

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4925 of file predicate.c.

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

Referenced by PrepareTransaction().

4926 {
4927  PREDICATELOCK *predlock;
4928  SERIALIZABLEXACT *sxact;
4929  TwoPhasePredicateRecord record;
4930  TwoPhasePredicateXactRecord *xactRecord;
4931  TwoPhasePredicateLockRecord *lockRecord;
4932 
4933  sxact = MySerializableXact;
4934  xactRecord = &(record.data.xactRecord);
4935  lockRecord = &(record.data.lockRecord);
4936 
4938  return;
4939 
4940  /* Generate an xact record for our SERIALIZABLEXACT */
4942  xactRecord->xmin = MySerializableXact->xmin;
4943  xactRecord->flags = MySerializableXact->flags;
4944 
4945  /*
4946  * Note that we don't include the list of conflicts in our out in the
4947  * statefile, because new conflicts can be added even after the
4948  * transaction prepares. We'll just make a conservative assumption during
4949  * recovery instead.
4950  */
4951 
4953  &record, sizeof(record));
4954 
4955  /*
4956  * Generate a lock record for each lock.
4957  *
4958  * To do this, we need to walk the predicate lock list in our sxact rather
4959  * than using the local predicate lock table because the latter is not
4960  * guaranteed to be accurate.
4961  */
4962  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4963 
4964  /*
4965  * No need to take sxact->perXactPredicateListLock in parallel mode
4966  * because there cannot be any parallel workers running while we are
4967  * preparing a transaction.
4968  */
4970 
4971  predlock = (PREDICATELOCK *)
4972  SHMQueueNext(&(sxact->predicateLocks),
4973  &(sxact->predicateLocks),
4974  offsetof(PREDICATELOCK, xactLink));
4975 
4976  while (predlock != NULL)
4977  {
4979  lockRecord->target = predlock->tag.myTarget->tag;
4980 
4982  &record, sizeof(record));
4983 
4984  predlock = (PREDICATELOCK *)
4985  SHMQueueNext(&(sxact->predicateLocks),
4986  &(predlock->xactLink),
4987  offsetof(PREDICATELOCK, xactLink));
4988  }
4989 
4990  LWLockRelease(SerializablePredicateListLock);
4991 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
TwoPhasePredicateRecordType type
PREDICATELOCKTARGETTAG target
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1182
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define TWOPHASE_RM_PREDICATELOCK_ID
Definition: twophase_rmgr.h:28
TwoPhasePredicateXactRecord xactRecord
#define InvalidSerializableXact
#define IsParallelWorker()
Definition: parallel.h:61
bool ParallelContextActive(void)
Definition: parallel.c:979
PREDICATELOCKTAG tag
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
TwoPhasePredicateLockRecord lockRecord
union TwoPhasePredicateRecord::@106 data
#define offsetof(type, field)
Definition: c.h:727
PREDICATELOCKTARGET * myTarget

◆ AttachSerializableXact()

void AttachSerializableXact ( SerializableXactHandle  handle)

Definition at line 5195 of file predicate.c.

References Assert, CreateLocalPredicateLockHash(), and InvalidSerializableXact.

Referenced by ParallelWorkerMain().

5196 {
5197 
5199 
5200  MySerializableXact = (SERIALIZABLEXACT *) handle;
5203 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
#define InvalidSerializableXact
#define Assert(condition)
Definition: c.h:804
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1922

◆ CheckAndPromotePredicateLockRequest()

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2318 of file predicate.c.

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

Referenced by PredicateLockAcquire().

2319 {
2320  PREDICATELOCKTARGETTAG targettag,
2321  nexttag,
2322  promotiontag;
2323  LOCALPREDICATELOCK *parentlock;
2324  bool found,
2325  promote;
2326 
2327  promote = false;
2328 
2329  targettag = *reqtag;
2330 
2331  /* check parents iteratively */
2332  while (GetParentPredicateLockTag(&targettag, &nexttag))
2333  {
2334  targettag = nexttag;
2336  &targettag,
2337  HASH_ENTER,
2338  &found);
2339  if (!found)
2340  {
2341  parentlock->held = false;
2342  parentlock->childLocks = 1;
2343  }
2344  else
2345  parentlock->childLocks++;
2346 
2347  if (parentlock->childLocks >
2348  MaxPredicateChildLocks(&targettag))
2349  {
2350  /*
2351  * We should promote to this parent lock. Continue to check its
2352  * ancestors, however, both to get their child counts right and to
2353  * check whether we should just go ahead and promote to one of
2354  * them.
2355  */
2356  promotiontag = targettag;
2357  promote = true;
2358  }
2359  }
2360 
2361  if (promote)
2362  {
2363  /* acquire coarsest ancestor eligible for promotion */
2364  PredicateLockAcquire(&promotiontag);
2365  return true;
2366  }
2367  else
2368  return false;
2369 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2510
static int MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag)
Definition: predicate.c:2281
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:2054
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409

◆ CheckForSerializableConflictIn()

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

Definition at line 4446 of file predicate.c.

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

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

4447 {
4448  PREDICATELOCKTARGETTAG targettag;
4449 
4450  if (!SerializationNeededForWrite(relation))
4451  return;
4452 
4453  /* Check if someone else has already decided that we need to die */
4455  ereport(ERROR,
4456  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4457  errmsg("could not serialize access due to read/write dependencies among transactions"),
4458  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4459  errhint("The transaction might succeed if retried.")));
4460 
4461  /*
4462  * We're doing a write which might cause rw-conflicts now or later.
4463  * Memorize that fact.
4464  */
4465  MyXactDidWrite = true;
4466 
4467  /*
4468  * It is important that we check for locks from the finest granularity to
4469  * the coarsest granularity, so that granularity promotion doesn't cause
4470  * us to miss a lock. The new (coarser) lock will be acquired before the
4471  * old (finer) locks are released.
4472  *
4473  * It is not possible to take and hold a lock across the checks for all
4474  * granularities because each target could be in a separate partition.
4475  */
4476  if (tid != NULL)
4477  {
4479  relation->rd_node.dbNode,
4480  relation->rd_id,
4483  CheckTargetForConflictsIn(&targettag);
4484  }
4485 
4486  if (blkno != InvalidBlockNumber)
4487  {
4489  relation->rd_node.dbNode,
4490  relation->rd_id,
4491  blkno);
4492  CheckTargetForConflictsIn(&targettag);
4493  }
4494 
4496  relation->rd_node.dbNode,
4497  relation->rd_id);
4498  CheckTargetForConflictsIn(&targettag);
4499 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
int errhint(const char *fmt,...)
Definition: elog.c:1152
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4264
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
int errcode(int sqlerrcode)
Definition: elog.c:694
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:558
#define SET_PREDICATELOCKTARGETTAG_TUPLE(locktag, dboid, reloid, blocknum, offnum)
#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag, dboid, reloid)
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1065
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define ERROR
Definition: elog.h:45
Oid rd_id
Definition: rel.h:112
#define ereport(elevel,...)
Definition: elog.h:155
RelFileNode rd_node
Definition: rel.h:55
#define InvalidBlockNumber
Definition: block.h:33
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
int errmsg(const char *fmt,...)
Definition: elog.c:905
static bool MyXactDidWrite
Definition: predicate.c:417
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98

◆ CheckForSerializableConflictOut()

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

Definition at line 4121 of file predicate.c.

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

Referenced by HeapCheckForSerializableConflictOut().

4122 {
4123  SERIALIZABLEXIDTAG sxidtag;
4124  SERIALIZABLEXID *sxid;
4125  SERIALIZABLEXACT *sxact;
4126 
4127  if (!SerializationNeededForRead(relation, snapshot))
4128  return;
4129 
4130  /* Check if someone else has already decided that we need to die */
4132  {
4133  ereport(ERROR,
4134  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4135  errmsg("could not serialize access due to read/write dependencies among transactions"),
4136  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4137  errhint("The transaction might succeed if retried.")));
4138  }
4140 
4142  return;
4143 
4144  /*
4145  * Find sxact or summarized info for the top level xid.
4146  */
4147  sxidtag.xid = xid;
4148  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4149  sxid = (SERIALIZABLEXID *)
4150  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4151  if (!sxid)
4152  {
4153  /*
4154  * Transaction not found in "normal" SSI structures. Check whether it
4155  * got pushed out to SLRU storage for "old committed" transactions.
4156  */
4157  SerCommitSeqNo conflictCommitSeqNo;
4158 
4159  conflictCommitSeqNo = SerialGetMinConflictCommitSeqNo(xid);
4160  if (conflictCommitSeqNo != 0)
4161  {
4162  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4164  || conflictCommitSeqNo
4166  ereport(ERROR,
4167  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4168  errmsg("could not serialize access due to read/write dependencies among transactions"),
4169  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4170  errhint("The transaction might succeed if retried.")));
4171 
4174  ereport(ERROR,
4175  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4176  errmsg("could not serialize access due to read/write dependencies among transactions"),
4177  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4178  errhint("The transaction might succeed if retried.")));
4179 
4181  }
4182 
4183  /* It's not serializable or otherwise not important. */
4184  LWLockRelease(SerializableXactHashLock);
4185  return;
4186  }
4187  sxact = sxid->myXact;
4188  Assert(TransactionIdEquals(sxact->topXid, xid));
4189  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4190  {
4191  /* Can't conflict with ourself or a transaction that will roll back. */
4192  LWLockRelease(SerializableXactHashLock);
4193  return;
4194  }
4195 
4196  /*
4197  * We have a conflict out to a transaction which has a conflict out to a
4198  * summarized transaction. That summarized transaction must have
4199  * committed first, and we can't tell when it committed in relation to our
4200  * snapshot acquisition, so something needs to be canceled.
4201  */
4202  if (SxactHasSummaryConflictOut(sxact))
4203  {
4204  if (!SxactIsPrepared(sxact))
4205  {
4206  sxact->flags |= SXACT_FLAG_DOOMED;
4207  LWLockRelease(SerializableXactHashLock);
4208  return;
4209  }
4210  else
4211  {
4212  LWLockRelease(SerializableXactHashLock);
4213  ereport(ERROR,
4214  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4215  errmsg("could not serialize access due to read/write dependencies among transactions"),
4216  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4217  errhint("The transaction might succeed if retried.")));
4218  }
4219  }
4220 
4221  /*
4222  * If this is a read-only transaction and the writing transaction has
4223  * committed, and it doesn't have a rw-conflict to a transaction which
4224  * committed before it, no conflict.
4225  */
4227  && SxactIsCommitted(sxact)
4228  && !SxactHasSummaryConflictOut(sxact)
4229  && (!SxactHasConflictOut(sxact)
4231  {
4232  /* Read-only transaction will appear to run first. No conflict. */
4233  LWLockRelease(SerializableXactHashLock);
4234  return;
4235  }
4236 
4237  if (!XidIsConcurrent(xid))
4238  {
4239  /* This write was already in our snapshot; no conflict. */
4240  LWLockRelease(SerializableXactHashLock);
4241  return;
4242  }
4243 
4245  {
4246  /* We don't want duplicate conflict records in the list. */
4247  LWLockRelease(SerializableXactHashLock);
4248  return;
4249  }
4250 
4251  /*
4252  * Flag the conflict. But first, if this conflict creates a dangerous
4253  * structure, ereport an error.
4254  */
4256  LWLockRelease(SerializableXactHashLock);
4257 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:653
int errhint(const char *fmt,...)
Definition: elog.c:1152
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4621
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:277
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:4063
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
int errcode(int sqlerrcode)
Definition: elog.c:694
static HTAB * SerializableXidHash
Definition: predicate.c:391
SERIALIZABLEXACT * myXact
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
#define SxactIsPrepared(sxact)
Definition: predicate.c:273
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:977
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1065
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define ERROR
Definition: elog.h:45
SerCommitSeqNo lastCommitBeforeSnapshot
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:425
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:278
#define InvalidSerCommitSeqNo
bool SHMQueueEmpty(const SHM_QUEUE *queue)
Definition: shmqueue.c:180
SerCommitSeqNo earliestOutConflictCommit
#define ereport(elevel,...)
Definition: elog.h:155
uint64 SerCommitSeqNo
#define SXACT_FLAG_DOOMED
#define SxactHasConflictOut(sxact)
Definition: predicate.c:284
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:514
int errmsg(const char *fmt,...)
Definition: elog.c:905
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define SxactIsCommitted(sxact)
Definition: predicate.c:272
union SERIALIZABLEXACT::@105 SeqNo

◆ CheckForSerializableConflictOutNeeded()

bool CheckForSerializableConflictOutNeeded ( Relation  relation,
Snapshot  snapshot 
)

Definition at line 4089 of file predicate.c.

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

Referenced by HeapCheckForSerializableConflictOut().

4090 {
4091  if (!SerializationNeededForRead(relation, snapshot))
4092  return false;
4093 
4094  /* Check if someone else has already decided that we need to die */
4096  {
4097  ereport(ERROR,
4098  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4099  errmsg("could not serialize access due to read/write dependencies among transactions"),
4100  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4101  errhint("The transaction might succeed if retried.")));
4102  }
4103 
4104  return true;
4105 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
int errhint(const char *fmt,...)
Definition: elog.c:1152
int errcode(int sqlerrcode)
Definition: elog.c:694
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1065
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define ERROR
Definition: elog.h:45
#define ereport(elevel,...)
Definition: elog.h:155
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:514
int errmsg(const char *fmt,...)
Definition: elog.c:905

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 1069 of file predicate.c.

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

Referenced by CheckPointGuts().

1070 {
1071  int tailPage;
1072 
1073  LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
1074 
1075  /* Exit quickly if the SLRU is currently not in use. */
1076  if (serialControl->headPage < 0)
1077  {
1078  LWLockRelease(SerialSLRULock);
1079  return;
1080  }
1081 
1083  {
1084  /* We can truncate the SLRU up to the page containing tailXid */
1085  tailPage = SerialPage(serialControl->tailXid);
1086  }
1087  else
1088  {
1089  /*----------
1090  * The SLRU is no longer needed. Truncate to head before we set head
1091  * invalid.
1092  *
1093  * XXX: It's possible that the SLRU is not needed again until XID
1094  * wrap-around has happened, so that the segment containing headPage
1095  * that we leave behind will appear to be new again. In that case it
1096  * won't be removed until XID horizon advances enough to make it
1097  * current again.
1098  *
1099  * XXX: This should happen in vac_truncate_clog(), not in checkpoints.
1100  * Consider this scenario, starting from a system with no in-progress
1101  * transactions and VACUUM FREEZE having maximized oldestXact:
1102  * - Start a SERIALIZABLE transaction.
1103  * - Start, finish, and summarize a SERIALIZABLE transaction, creating
1104  * one SLRU page.
1105  * - Consume XIDs to reach xidStopLimit.
1106  * - Finish all transactions. Due to the long-running SERIALIZABLE
1107  * transaction, earlier checkpoints did not touch headPage. The
1108  * next checkpoint will change it, but that checkpoint happens after
1109  * the end of the scenario.
1110  * - VACUUM to advance XID limits.
1111  * - Consume ~2M XIDs, crossing the former xidWrapLimit.
1112  * - Start, finish, and summarize a SERIALIZABLE transaction.
1113  * SerialAdd() declines to create the targetPage, because headPage
1114  * is not regarded as in the past relative to that targetPage. The
1115  * transaction instigating the summarize fails in
1116  * SimpleLruReadPage().
1117  */
1118  tailPage = serialControl->headPage;
1119  serialControl->headPage = -1;
1120  }
1121 
1122  LWLockRelease(SerialSLRULock);
1123 
1124  /* Truncate away pages that are no longer required */
1125  SimpleLruTruncate(SerialSlruCtl, tailPage);
1126 
1127  /*
1128  * Write dirty SLRU pages to disk
1129  *
1130  * This is not actually necessary from a correctness point of view. We do
1131  * it merely as a debugging aid.
1132  *
1133  * We're doing this after the truncation to avoid writing pages right
1134  * before deleting the file in which they sit, which would be completely
1135  * pointless.
1136  */
1138 }
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1225
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define SerialSlruCtl
Definition: predicate.c:321
#define SerialPage(xid)
Definition: predicate.c:338
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1155
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
TransactionId tailXid
Definition: predicate.c:344
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static SerialControl serialControl
Definition: predicate.c:349

◆ CheckTableForSerializableConflictIn()

void CheckTableForSerializableConflictIn ( Relation  relation)

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

4530 {
4531  HASH_SEQ_STATUS seqstat;
4532  PREDICATELOCKTARGET *target;
4533  Oid dbId;
4534  Oid heapId;
4535  int i;
4536 
4537  /*
4538  * Bail out quickly if there are no serializable transactions running.
4539  * It's safe to check this without taking locks because the caller is
4540  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4541  * would matter here can be acquired while that is held.
4542  */
4544  return;
4545 
4546  if (!SerializationNeededForWrite(relation))
4547  return;
4548 
4549  /*
4550  * We're doing a write which might cause rw-conflicts now or later.
4551  * Memorize that fact.
4552  */
4553  MyXactDidWrite = true;
4554 
4555  Assert(relation->rd_index == NULL); /* not an index relation */
4556 
4557  dbId = relation->rd_node.dbNode;
4558  heapId = relation->rd_id;
4559 
4560  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
4561  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4563  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4564 
4565  /* Scan through target list */
4567 
4568  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4569  {
4570  PREDICATELOCK *predlock;
4571 
4572  /*
4573  * Check whether this is a target which needs attention.
4574  */
4575  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4576  continue; /* wrong relation id */
4577  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4578  continue; /* wrong database id */
4579 
4580  /*
4581  * Loop through locks for this target and flag conflicts.
4582  */
4583  predlock = (PREDICATELOCK *)
4584  SHMQueueNext(&(target->predicateLocks),
4585  &(target->predicateLocks),
4586  offsetof(PREDICATELOCK, targetLink));
4587  while (predlock)
4588  {
4589  PREDICATELOCK *nextpredlock;
4590 
4591  nextpredlock = (PREDICATELOCK *)
4592  SHMQueueNext(&(target->predicateLocks),
4593  &(predlock->targetLink),
4594  offsetof(PREDICATELOCK, targetLink));
4595 
4596  if (predlock->tag.myXact != MySerializableXact
4598  {
4600  }
4601 
4602  predlock = nextpredlock;
4603  }
4604  }
4605 
4606  /* Release locks in reverse order */
4607  LWLockRelease(SerializableXactHashLock);
4608  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4610  LWLockRelease(SerializablePredicateListLock);
4611 }
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:653
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4621
static PredXactList PredXact
Definition: predicate.c:379
TransactionId SxactGlobalXmin
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:558
unsigned int Oid
Definition: postgres_ext.h:31
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
Form_pg_index rd_index
Definition: rel.h:175
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
Oid rd_id
Definition: rel.h:112
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:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:256
int i
SERIALIZABLEXACT * myXact
static bool MyXactDidWrite
Definition: predicate.c:417
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define offsetof(type, field)
Definition: c.h:727
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:119

◆ CheckTargetForConflictsIn()

static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag)
static

Definition at line 4264 of file predicate.c.

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

Referenced by CheckForSerializableConflictIn().

4265 {
4266  uint32 targettaghash;
4267  LWLock *partitionLock;
4268  PREDICATELOCKTARGET *target;
4269  PREDICATELOCK *predlock;
4270  PREDICATELOCK *mypredlock = NULL;
4271  PREDICATELOCKTAG mypredlocktag;
4272 
4274 
4275  /*
4276  * The same hash and LW lock apply to the lock target and the lock itself.
4277  */
4278  targettaghash = PredicateLockTargetTagHashCode(targettag);
4279  partitionLock = PredicateLockHashPartitionLock(targettaghash);
4280  LWLockAcquire(partitionLock, LW_SHARED);
4281  target = (PREDICATELOCKTARGET *)
4283  targettag, targettaghash,
4284  HASH_FIND, NULL);
4285  if (!target)
4286  {
4287  /* Nothing has this target locked; we're done here. */
4288  LWLockRelease(partitionLock);
4289  return;
4290  }
4291 
4292  /*
4293  * Each lock for an overlapping transaction represents a conflict: a
4294  * rw-dependency in to this transaction.
4295  */
4296  predlock = (PREDICATELOCK *)
4297  SHMQueueNext(&(target->predicateLocks),
4298  &(target->predicateLocks),
4299  offsetof(PREDICATELOCK, targetLink));
4300  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4301  while (predlock)
4302  {
4303  SHM_QUEUE *predlocktargetlink;
4304  PREDICATELOCK *nextpredlock;
4305  SERIALIZABLEXACT *sxact;
4306 
4307  predlocktargetlink = &(predlock->targetLink);
4308  nextpredlock = (PREDICATELOCK *)
4309  SHMQueueNext(&(target->predicateLocks),
4310  predlocktargetlink,
4311  offsetof(PREDICATELOCK, targetLink));
4312 
4313  sxact = predlock->tag.myXact;
4314  if (sxact == MySerializableXact)
4315  {
4316  /*
4317  * If we're getting a write lock on a tuple, we don't need a
4318  * predicate (SIREAD) lock on the same tuple. We can safely remove
4319  * our SIREAD lock, but we'll defer doing so until after the loop
4320  * because that requires upgrading to an exclusive partition lock.
4321  *
4322  * We can't use this optimization within a subtransaction because
4323  * the subtransaction could roll back, and we would be left
4324  * without any lock at the top level.
4325  */
4326  if (!IsSubTransaction()
4327  && GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
4328  {
4329  mypredlock = predlock;
4330  mypredlocktag = predlock->tag;
4331  }
4332  }
4333  else if (!SxactIsDoomed(sxact)
4334  && (!SxactIsCommitted(sxact)
4336  sxact->finishedBefore))
4338  {
4339  LWLockRelease(SerializableXactHashLock);
4340  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4341 
4342  /*
4343  * Re-check after getting exclusive lock because the other
4344  * transaction may have flagged a conflict.
4345  */
4346  if (!SxactIsDoomed(sxact)
4347  && (!SxactIsCommitted(sxact)
4349  sxact->finishedBefore))
4351  {
4353  }
4354 
4355  LWLockRelease(SerializableXactHashLock);
4356  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4357  }
4358 
4359  predlock = nextpredlock;
4360  }
4361  LWLockRelease(SerializableXactHashLock);
4362  LWLockRelease(partitionLock);
4363 
4364  /*
4365  * If we found one of our own SIREAD locks to remove, remove it now.
4366  *
4367  * At this point our transaction already has a RowExclusiveLock on the
4368  * relation, so we are OK to drop the predicate lock on the tuple, if
4369  * found, without fearing that another write against the tuple will occur
4370  * before the MVCC information makes it to the buffer.
4371  */
4372  if (mypredlock != NULL)
4373  {
4374  uint32 predlockhashcode;
4375  PREDICATELOCK *rmpredlock;
4376 
4377  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4378  if (IsInParallelMode())
4380  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4381  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4382 
4383  /*
4384  * Remove the predicate lock from shared memory, if it wasn't removed
4385  * while the locks were released. One way that could happen is from
4386  * autovacuum cleaning up an index.
4387  */
4388  predlockhashcode = PredicateLockHashCodeFromTargetHashCode
4389  (&mypredlocktag, targettaghash);
4390  rmpredlock = (PREDICATELOCK *)
4392  &mypredlocktag,
4393  predlockhashcode,
4394  HASH_FIND, NULL);
4395  if (rmpredlock != NULL)
4396  {
4397  Assert(rmpredlock == mypredlock);
4398 
4399  SHMQueueDelete(&(mypredlock->targetLink));
4400  SHMQueueDelete(&(mypredlock->xactLink));
4401 
4402  rmpredlock = (PREDICATELOCK *)
4404  &mypredlocktag,
4405  predlockhashcode,
4406  HASH_REMOVE, NULL);
4407  Assert(rmpredlock == mypredlock);
4408 
4409  RemoveTargetIfNoLongerUsed(target, targettaghash);
4410  }
4411 
4412  LWLockRelease(SerializableXactHashLock);
4413  LWLockRelease(partitionLock);
4414  if (IsInParallelMode())
4416  LWLockRelease(SerializablePredicateListLock);
4417 
4418  if (rmpredlock != NULL)
4419  {
4420  /*
4421  * Remove entry in local lock table if it exists. It's OK if it
4422  * doesn't exist; that means the lock was transferred to a new
4423  * target by a different backend.
4424  */
4426  targettag, targettaghash,
4427  HASH_REMOVE, NULL);
4428 
4429  DecrementParentLocks(targettag);
4430  }
4431  }
4432 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:967
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
TransactionId finishedBefore
Definition: lwlock.h:31
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:653
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4621
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2165
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:250
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag)
bool IsInParallelMode(void)
Definition: xact.c:1012
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
static HTAB * PredicateLockHash
Definition: predicate.c:393
#define InvalidSerializableXact
unsigned int uint32
Definition: c.h:441
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2383
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:804
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
bool IsSubTransaction(void)
Definition: xact.c:4756
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
SERIALIZABLEXACT * myXact
#define SxactIsCommitted(sxact)
Definition: predicate.c:272
#define offsetof(type, field)
Definition: c.h:727

◆ ClearOldPredicateLocks()

static void ClearOldPredicateLocks ( void  )
static

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

3744 {
3745  SERIALIZABLEXACT *finishedSxact;
3746  PREDICATELOCK *predlock;
3747 
3748  /*
3749  * Loop through finished transactions. They are in commit order, so we can
3750  * stop as soon as we find one that's still interesting.
3751  */
3752  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3753  finishedSxact = (SERIALIZABLEXACT *)
3756  offsetof(SERIALIZABLEXACT, finishedLink));
3757  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3758  while (finishedSxact)
3759  {
3760  SERIALIZABLEXACT *nextSxact;
3761 
3762  nextSxact = (SERIALIZABLEXACT *)
3764  &(finishedSxact->finishedLink),
3765  offsetof(SERIALIZABLEXACT, finishedLink));
3769  {
3770  /*
3771  * This transaction committed before any in-progress transaction
3772  * took its snapshot. It's no longer interesting.
3773  */
3774  LWLockRelease(SerializableXactHashLock);
3775  SHMQueueDelete(&(finishedSxact->finishedLink));
3776  ReleaseOneSerializableXact(finishedSxact, false, false);
3777  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3778  }
3779  else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3780  && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3781  {
3782  /*
3783  * Any active transactions that took their snapshot before this
3784  * transaction committed are read-only, so we can clear part of
3785  * its state.
3786  */
3787  LWLockRelease(SerializableXactHashLock);
3788 
3789  if (SxactIsReadOnly(finishedSxact))
3790  {
3791  /* A read-only transaction can be removed entirely */
3792  SHMQueueDelete(&(finishedSxact->finishedLink));
3793  ReleaseOneSerializableXact(finishedSxact, false, false);
3794  }
3795  else
3796  {
3797  /*
3798  * A read-write transaction can only be partially cleared. We
3799  * need to keep the SERIALIZABLEXACT but can release the
3800  * SIREAD locks and conflicts in.
3801  */
3802  ReleaseOneSerializableXact(finishedSxact, true, false);
3803  }
3804 
3806  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3807  }
3808  else
3809  {
3810  /* Still interesting. */
3811  break;
3812  }
3813  finishedSxact = nextSxact;
3814  }
3815  LWLockRelease(SerializableXactHashLock);
3816 
3817  /*
3818  * Loop through predicate locks on dummy transaction for summarized data.
3819  */
3820  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
3821  predlock = (PREDICATELOCK *)
3824  offsetof(PREDICATELOCK, xactLink));
3825  while (predlock)
3826  {
3827  PREDICATELOCK *nextpredlock;
3828  bool canDoPartialCleanup;
3829 
3830  nextpredlock = (PREDICATELOCK *)
3832  &predlock->xactLink,
3833  offsetof(PREDICATELOCK, xactLink));
3834 
3835  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3836  Assert(predlock->commitSeqNo != 0);
3838  canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
3839  LWLockRelease(SerializableXactHashLock);
3840 
3841  /*
3842  * If this lock originally belonged to an old enough transaction, we
3843  * can release it.
3844  */
3845  if (canDoPartialCleanup)
3846  {
3847  PREDICATELOCKTAG tag;
3848  PREDICATELOCKTARGET *target;
3849  PREDICATELOCKTARGETTAG targettag;
3850  uint32 targettaghash;
3851  LWLock *partitionLock;
3852 
3853  tag = predlock->tag;
3854  target = tag.myTarget;
3855  targettag = target->tag;
3856  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3857  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3858 
3859  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3860 
3861  SHMQueueDelete(&(predlock->targetLink));
3862  SHMQueueDelete(&(predlock->xactLink));
3863 
3866  targettaghash),
3867  HASH_REMOVE, NULL);
3868  RemoveTargetIfNoLongerUsed(target, targettaghash);
3869 
3870  LWLockRelease(partitionLock);
3871  }
3872 
3873  predlock = nextpredlock;
3874  }
3875 
3876  LWLockRelease(SerializablePredicateListLock);
3877  LWLockRelease(SerializableFinishedListLock);
3878 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:967
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
TransactionId finishedBefore
Definition: lwlock.h:31
static PredXactList PredXact
Definition: predicate.c:379
TransactionId SxactGlobalXmin
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2165
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
static HTAB * PredicateLockHash
Definition: predicate.c:393
unsigned int uint32
Definition: c.h:441
#define InvalidSerCommitSeqNo
SerCommitSeqNo commitSeqNo
SerCommitSeqNo HavePartialClearedThrough
PREDICATELOCKTAG tag
SerCommitSeqNo CanPartialClearThrough
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
SerCommitSeqNo commitSeqNo
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize)
Definition: predicate.c:3900
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:357
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static SHM_QUEUE * FinishedSerializableTransactions
Definition: predicate.c:394
#define offsetof(type, field)
Definition: c.h:727
PREDICATELOCKTARGET * myTarget

◆ CoarserLockCovers()

static bool CoarserLockCovers ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2093 of file predicate.c.

References GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

2094 {
2095  PREDICATELOCKTARGETTAG targettag,
2096  parenttag;
2097 
2098  targettag = *newtargettag;
2099 
2100  /* check parents iteratively until no more */
2101  while (GetParentPredicateLockTag(&targettag, &parenttag))
2102  {
2103  targettag = parenttag;
2104  if (PredicateLockExists(&targettag))
2105  return true;
2106  }
2107 
2108  /* no more parents to check; lock is not covered */
2109  return false;
2110 }
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2027
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:2054

◆ CreateLocalPredicateLockHash()

static void CreateLocalPredicateLockHash ( void  )
static

Definition at line 1922 of file predicate.c.

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

Referenced by AttachSerializableXact(), and GetSerializableTransactionSnapshotInt().

1923 {
1924  HASHCTL hash_ctl;
1925 
1926  /* Initialize the backend-local hash table of parent locks */
1927  Assert(LocalPredicateLockHash == NULL);
1928  hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1929  hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1930  LocalPredicateLockHash = hash_create("Local predicate lock",
1932  &hash_ctl,
1933  HASH_ELEM | HASH_BLOBS);
1934 }
#define HASH_ELEM
Definition: hsearch.h:95
Size entrysize
Definition: hsearch.h:76
int max_predicate_locks_per_xact
Definition: predicate.c:366
struct LOCALPREDICATELOCK LOCALPREDICATELOCK
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
#define HASH_BLOBS
Definition: hsearch.h:97
Size keysize
Definition: hsearch.h:75
#define Assert(condition)
Definition: c.h:804
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409

◆ CreatePredicateLock()

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

Definition at line 2445 of file predicate.c.

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

Referenced by predicatelock_twophase_recover(), and PredicateLockAcquire().

2448 {
2449  PREDICATELOCKTARGET *target;
2450  PREDICATELOCKTAG locktag;
2451  PREDICATELOCK *lock;
2452  LWLock *partitionLock;
2453  bool found;
2454 
2455  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2456 
2457  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2458  if (IsInParallelMode())
2460  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2461 
2462  /* Make sure that the target is represented. */
2463  target = (PREDICATELOCKTARGET *)
2465  targettag, targettaghash,
2466  HASH_ENTER_NULL, &found);
2467  if (!target)
2468  ereport(ERROR,
2469  (errcode(ERRCODE_OUT_OF_MEMORY),
2470  errmsg("out of shared memory"),
2471  errhint("You might need to increase max_pred_locks_per_transaction.")));
2472  if (!found)
2473  SHMQueueInit(&(target->predicateLocks));
2474 
2475  /* We've got the sxact and target, make sure they're joined. */
2476  locktag.myTarget = target;
2477  locktag.myXact = sxact;
2478  lock = (PREDICATELOCK *)
2480  PredicateLockHashCodeFromTargetHashCode(&locktag, targettaghash),
2481  HASH_ENTER_NULL, &found);
2482  if (!lock)
2483  ereport(ERROR,
2484  (errcode(ERRCODE_OUT_OF_MEMORY),
2485  errmsg("out of shared memory"),
2486  errhint("You might need to increase max_pred_locks_per_transaction.")));
2487 
2488  if (!found)
2489  {
2490  SHMQueueInsertBefore(&(target->predicateLocks), &(lock->targetLink));
2492  &(lock->xactLink));
2494  }
2495 
2496  LWLockRelease(partitionLock);
2497  if (IsInParallelMode())
2499  LWLockRelease(SerializablePredicateListLock);
2500 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:967
Definition: lwlock.h:31
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
int errhint(const char *fmt,...)
Definition: elog.c:1152
int errcode(int sqlerrcode)
Definition: elog.c:694
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
bool IsInParallelMode(void)
Definition: xact.c:1012
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
#define ERROR
Definition: elog.h:45
static HTAB * PredicateLockHash
Definition: predicate.c:393
#define InvalidSerCommitSeqNo
#define ereport(elevel,...)
Definition: elog.h:155
SerCommitSeqNo commitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
int errmsg(const char *fmt,...)
Definition: elog.c:905
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
SERIALIZABLEXACT * myXact
PREDICATELOCKTARGET * myTarget

◆ CreatePredXact()

static SERIALIZABLEXACT * CreatePredXact ( void  )
static

Definition at line 580 of file predicate.c.

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

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

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

◆ DecrementParentLocks()

static void DecrementParentLocks ( const PREDICATELOCKTARGETTAG targettag)
static

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

2384 {
2385  PREDICATELOCKTARGETTAG parenttag,
2386  nexttag;
2387 
2388  parenttag = *targettag;
2389 
2390  while (GetParentPredicateLockTag(&parenttag, &nexttag))
2391  {
2392  uint32 targettaghash;
2393  LOCALPREDICATELOCK *parentlock,
2394  *rmlock PG_USED_FOR_ASSERTS_ONLY;
2395 
2396  parenttag = nexttag;
2397  targettaghash = PredicateLockTargetTagHashCode(&parenttag);
2398  parentlock = (LOCALPREDICATELOCK *)
2400  &parenttag, targettaghash,
2401  HASH_FIND, NULL);
2402 
2403  /*
2404  * There's a small chance the parent lock doesn't exist in the lock
2405  * table. This can happen if we prematurely removed it because an
2406  * index split caused the child refcount to be off.
2407  */
2408  if (parentlock == NULL)
2409  continue;
2410 
2411  parentlock->childLocks--;
2412 
2413  /*
2414  * Under similar circumstances the parent lock's refcount might be
2415  * zero. This only happens if we're holding that lock (otherwise we
2416  * would have removed the entry).
2417  */
2418  if (parentlock->childLocks < 0)
2419  {
2420  Assert(parentlock->held);
2421  parentlock->childLocks = 0;
2422  }
2423 
2424  if ((parentlock->childLocks == 0) && (!parentlock->held))
2425  {
2426  rmlock = (LOCALPREDICATELOCK *)
2428  &parenttag, targettaghash,
2429  HASH_REMOVE, NULL);
2430  Assert(rmlock == parentlock);
2431  }
2432  }
2433 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:967
unsigned int uint32
Definition: c.h:441
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:2054
#define Assert(condition)
Definition: c.h:804
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:155

◆ DeleteChildTargetLocks()

static void DeleteChildTargetLocks ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2196 of file predicate.c.

References Assert, DecrementParentLocks(), HASH_REMOVE, hash_search_with_hash_value(), IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, offsetof, SERIALIZABLEXACT::perXactPredicateListLock, 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().

2197 {
2198  SERIALIZABLEXACT *sxact;
2199  PREDICATELOCK *predlock;
2200 
2201  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2202  sxact = MySerializableXact;
2203  if (IsInParallelMode())
2205  predlock = (PREDICATELOCK *)
2206  SHMQueueNext(&(sxact->predicateLocks),
2207  &(sxact->predicateLocks),
2208  offsetof(PREDICATELOCK, xactLink));
2209  while (predlock)
2210  {
2211  SHM_QUEUE *predlocksxactlink;
2212  PREDICATELOCK *nextpredlock;
2213  PREDICATELOCKTAG oldlocktag;
2214  PREDICATELOCKTARGET *oldtarget;
2215  PREDICATELOCKTARGETTAG oldtargettag;
2216 
2217  predlocksxactlink = &(predlock->xactLink);
2218  nextpredlock = (PREDICATELOCK *)
2219  SHMQueueNext(&(sxact->predicateLocks),
2220  predlocksxactlink,
2221  offsetof(PREDICATELOCK, xactLink));
2222 
2223  oldlocktag = predlock->tag;
2224  Assert(oldlocktag.myXact == sxact);
2225  oldtarget = oldlocktag.myTarget;
2226  oldtargettag = oldtarget->tag;
2227 
2228  if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
2229  {
2230  uint32 oldtargettaghash;
2231  LWLock *partitionLock;
2233 
2234  oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2235  partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2236 
2237  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2238 
2239  SHMQueueDelete(predlocksxactlink);
2240  SHMQueueDelete(&(predlock->targetLink));
2241  rmpredlock = hash_search_with_hash_value
2243  &oldlocktag,
2245  oldtargettaghash),
2246  HASH_REMOVE, NULL);
2247  Assert(rmpredlock == predlock);
2248 
2249  RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2250 
2251  LWLockRelease(partitionLock);
2252 
2253  DecrementParentLocks(&oldtargettag);
2254  }
2255 
2256  predlock = nextpredlock;
2257  }
2258  if (IsInParallelMode())
2260  LWLockRelease(SerializablePredicateListLock);
2261 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:967
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
Definition: lwlock.h:31
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2165
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
bool IsInParallelMode(void)
Definition: xact.c:1012
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
static HTAB * PredicateLockHash
Definition: predicate.c:393
unsigned int uint32
Definition: c.h:441
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2383
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
#define TargetTagIsCoveredBy(covered_target, covering_target)
Definition: predicate.c:228
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
SERIALIZABLEXACT * myXact
#define offsetof(type, field)
Definition: c.h:727
PREDICATELOCKTARGET * myTarget
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:155

◆ DeleteLockTarget()

static void DeleteLockTarget ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

Definition at line 2662 of file predicate.c.

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

Referenced by TransferPredicateLocksToNewTarget().

2663 {
2664  PREDICATELOCK *predlock;
2665  SHM_QUEUE *predlocktargetlink;
2666  PREDICATELOCK *nextpredlock;
2667  bool found;
2668 
2669  Assert(LWLockHeldByMeInMode(SerializablePredicateListLock,
2670  LW_EXCLUSIVE));
2672 
2673  predlock = (PREDICATELOCK *)
2674  SHMQueueNext(&(target->predicateLocks),
2675  &(target->predicateLocks),
2676  offsetof(PREDICATELOCK, targetLink));
2677  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2678  while (predlock)
2679  {
2680  predlocktargetlink = &(predlock->targetLink);
2681  nextpredlock = (PREDICATELOCK *)
2682  SHMQueueNext(&(target->predicateLocks),
2683  predlocktargetlink,
2684  offsetof(PREDICATELOCK, targetLink));
2685 
2686  SHMQueueDelete(&(predlock->xactLink));
2687  SHMQueueDelete(&(predlock->targetLink));
2688 
2691  &predlock->tag,
2693  targettaghash),
2694  HASH_REMOVE, &found);
2695  Assert(found);
2696 
2697  predlock = nextpredlock;
2698  }
2699  LWLockRelease(SerializableXactHashLock);
2700 
2701  /* Remove the target itself, if possible. */
2702  RemoveTargetIfNoLongerUsed(target, targettaghash);
2703 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:967
bool LWLockHeldByMeInMode(LWLock *l, LWLockMode mode)
Definition: lwlock.c:1942
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1924
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2165
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
static HTAB * PredicateLockHash
Definition: predicate.c:393
PREDICATELOCKTAG tag
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
#define offsetof(type, field)
Definition: c.h:727

◆ DropAllPredicateLocksFromTable()

static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
)
static

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

2951 {
2952  HASH_SEQ_STATUS seqstat;
2953  PREDICATELOCKTARGET *oldtarget;
2954  PREDICATELOCKTARGET *heaptarget;
2955  Oid dbId;
2956  Oid relId;
2957  Oid heapId;
2958  int i;
2959  bool isIndex;
2960  bool found;
2961  uint32 heaptargettaghash;
2962 
2963  /*
2964  * Bail out quickly if there are no serializable transactions running.
2965  * It's safe to check this without taking locks because the caller is
2966  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
2967  * would matter here can be acquired while that is held.
2968  */
2970  return;
2971 
2972  if (!PredicateLockingNeededForRelation(relation))
2973  return;
2974 
2975  dbId = relation->rd_node.dbNode;
2976  relId = relation->rd_id;
2977  if (relation->rd_index == NULL)
2978  {
2979  isIndex = false;
2980  heapId = relId;
2981  }
2982  else
2983  {
2984  isIndex = true;
2985  heapId = relation->rd_index->indrelid;
2986  }
2987  Assert(heapId != InvalidOid);
2988  Assert(transfer || !isIndex); /* index OID only makes sense with
2989  * transfer */
2990 
2991  /* Retrieve first time needed, then keep. */
2992  heaptargettaghash = 0;
2993  heaptarget = NULL;
2994 
2995  /* Acquire locks on all lock partitions */
2996  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
2997  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
2999  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3000 
3001  /*
3002  * Remove the dummy entry to give us scratch space, so we know we'll be
3003  * able to create the new lock target.
3004  */
3005  if (transfer)
3006  RemoveScratchTarget(true);
3007 
3008  /* Scan through target map */
3010 
3011  while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
3012  {
3013  PREDICATELOCK *oldpredlock;
3014 
3015  /*
3016  * Check whether this is a target which needs attention.
3017  */
3018  if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) != relId)
3019  continue; /* wrong relation id */
3020  if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
3021  continue; /* wrong database id */
3022  if (transfer && !isIndex
3024  continue; /* already the right lock */
3025 
3026  /*
3027  * If we made it here, we have work to do. We make sure the heap
3028  * relation lock exists, then we walk the list of predicate locks for
3029  * the old target we found, moving all locks to the heap relation lock
3030  * -- unless they already hold that.
3031  */
3032 
3033  /*
3034  * First make sure we have the heap relation target. We only need to
3035  * do this once.
3036  */
3037  if (transfer && heaptarget == NULL)
3038  {
3039  PREDICATELOCKTARGETTAG heaptargettag;
3040 
3041  SET_PREDICATELOCKTARGETTAG_RELATION(heaptargettag, dbId, heapId);
3042  heaptargettaghash = PredicateLockTargetTagHashCode(&heaptargettag);
3044  &heaptargettag,
3045  heaptargettaghash,
3046  HASH_ENTER, &found);
3047  if (!found)
3048  SHMQueueInit(&heaptarget->predicateLocks);
3049  }
3050 
3051  /*
3052  * Loop through all the locks on the old target, replacing them with
3053  * locks on the new target.
3054  */
3055  oldpredlock = (PREDICATELOCK *)
3056  SHMQueueNext(&(oldtarget->predicateLocks),
3057  &(oldtarget->predicateLocks),
3058  offsetof(PREDICATELOCK, targetLink));
3059  while (oldpredlock)
3060  {
3061  PREDICATELOCK *nextpredlock;
3062  PREDICATELOCK *newpredlock;
3063  SerCommitSeqNo oldCommitSeqNo;
3064  SERIALIZABLEXACT *oldXact;
3065 
3066  nextpredlock = (PREDICATELOCK *)
3067  SHMQueueNext(&(oldtarget->predicateLocks),
3068  &(oldpredlock->targetLink),
3069  offsetof(PREDICATELOCK, targetLink));
3070 
3071  /*
3072  * Remove the old lock first. This avoids the chance of running
3073  * out of lock structure entries for the hash table.
3074  */
3075  oldCommitSeqNo = oldpredlock->commitSeqNo;
3076  oldXact = oldpredlock->tag.myXact;
3077 
3078  SHMQueueDelete(&(oldpredlock->xactLink));
3079 
3080  /*
3081  * No need for retail delete from oldtarget list, we're removing
3082  * the whole target anyway.
3083  */
3085  &oldpredlock->tag,
3086  HASH_REMOVE, &found);
3087  Assert(found);
3088 
3089  if (transfer)
3090  {
3091  PREDICATELOCKTAG newpredlocktag;
3092 
3093  newpredlocktag.myTarget = heaptarget;
3094  newpredlocktag.myXact = oldXact;
3095  newpredlock = (PREDICATELOCK *)
3097  &newpredlocktag,
3099  heaptargettaghash),
3100  HASH_ENTER,
3101  &found);
3102  if (!found)
3103  {
3104  SHMQueueInsertBefore(&(heaptarget->predicateLocks),
3105  &(newpredlock->targetLink));
3106  SHMQueueInsertBefore(&(newpredlocktag.myXact->predicateLocks),
3107  &(newpredlock->xactLink));
3108  newpredlock->commitSeqNo = oldCommitSeqNo;
3109  }
3110  else
3111  {
3112  if (newpredlock->commitSeqNo < oldCommitSeqNo)
3113  newpredlock->commitSeqNo = oldCommitSeqNo;
3114  }
3115 
3116  Assert(newpredlock->commitSeqNo != 0);
3117  Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
3118  || (newpredlock->tag.myXact == OldCommittedSxact));
3119  }
3120 
3121  oldpredlock = nextpredlock;
3122  }
3123 
3125  &found);
3126  Assert(found);
3127  }
3128 
3129  /* Put the scratch entry back */
3130  if (transfer)
3131  RestoreScratchTarget(true);
3132 
3133  /* Release locks in reverse order */
3134  LWLockRelease(SerializableXactHashLock);
3135  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3137  LWLockRelease(SerializablePredicateListLock);
3138 }
#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:967
static bool PredicateLockingNeededForRelation(Relation relation)
Definition: predicate.c:495
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
static PredXactList PredXact
Definition: predicate.c:379
TransactionId SxactGlobalXmin
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
unsigned int Oid
Definition: postgres_ext.h:31
#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag, dboid, reloid)
static void RemoveScratchTarget(bool lockheld)
Definition: predicate.c:2122
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
Form_pg_index rd_index
Definition: rel.h:175
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
static HTAB * PredicateLockHash
Definition: predicate.c:393
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
unsigned int uint32
Definition: c.h:441
Oid rd_id
Definition: rel.h:112
#define InvalidSerCommitSeqNo
static void RestoreScratchTarget(bool lockheld)
Definition: predicate.c:2143
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define InvalidOid
Definition: postgres_ext.h:36
PREDICATELOCKTARGETTAG tag
RelFileNode rd_node
Definition: rel.h:55
SerCommitSeqNo commitSeqNo
uint64 SerCommitSeqNo
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:357
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:256
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
int i
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
SERIALIZABLEXACT * myXact
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define offsetof(type, field)
Definition: c.h:727
PREDICATELOCKTARGET * myTarget
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:119

◆ FirstPredXact()

static SERIALIZABLEXACT * FirstPredXact ( void  )
static

Definition at line 612 of file predicate.c.

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

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

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

◆ FlagRWConflict()

static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

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

4622 {
4623  Assert(reader != writer);
4624 
4625  /* First, see if this conflict causes failure. */
4627 
4628  /* Actually do the conflict flagging. */
4629  if (reader == OldCommittedSxact)
4631  else if (writer == OldCommittedSxact)
4633  else
4634  SetRWConflict(reader, writer);
4635 }
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:686
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4656
#define Assert(condition)
Definition: c.h:804
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:357
#define SXACT_FLAG_SUMMARY_CONFLICT_IN

◆ FlagSxactUnsafe()

static void FlagSxactUnsafe ( SERIALIZABLEXACT sxact)
static

Definition at line 750 of file predicate.c.

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

Referenced by ReleasePredicateLocks().

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

◆ GetParentPredicateLockTag()

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

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

2056 {
2057  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2058  {
2059  case PREDLOCKTAG_RELATION:
2060  /* relation locks have no parent lock */
2061  return false;
2062 
2063  case PREDLOCKTAG_PAGE:
2064  /* parent lock is relation lock */
2068 
2069  return true;
2070 
2071  case PREDLOCKTAG_TUPLE:
2072  /* parent lock is page lock */
2077  return true;
2078  }
2079 
2080  /* not reachable */
2081  Assert(false);
2082  return false;
2083 }
#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:804

◆ GetPredicateLockStatusData()

PredicateLockData* GetPredicateLockStatusData ( void  )

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

1444 {
1445  PredicateLockData *data;
1446  int i;
1447  int els,
1448  el;
1449  HASH_SEQ_STATUS seqstat;
1450  PREDICATELOCK *predlock;
1451 
1452  data = (PredicateLockData *) palloc(sizeof(PredicateLockData));
1453 
1454  /*
1455  * To ensure consistency, take simultaneous locks on all partition locks
1456  * in ascending order, then SerializableXactHashLock.
1457  */
1458  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
1460  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1461 
1462  /* Get number of locks and allocate appropriately-sized arrays. */
1464  data->nelements = els;
1465  data->locktags = (PREDICATELOCKTARGETTAG *)
1466  palloc(sizeof(PREDICATELOCKTARGETTAG) * els);
1467  data->xacts = (SERIALIZABLEXACT *)
1468  palloc(sizeof(SERIALIZABLEXACT) * els);
1469 
1470 
1471  /* Scan through PredicateLockHash and copy contents */
1472  hash_seq_init(&seqstat, PredicateLockHash);
1473 
1474  el = 0;
1475 
1476  while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
1477  {
1478  data->locktags[el] = predlock->tag.myTarget->tag;
1479  data->xacts[el] = *predlock->tag.myXact;
1480  el++;
1481  }
1482 
1483  Assert(el == els);
1484 
1485  /* Release locks in reverse order */
1486  LWLockRelease(SerializableXactHashLock);
1487  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1489 
1490  return data;
1491 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1382
SERIALIZABLEXACT * xacts
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
static HTAB * PredicateLockHash
Definition: predicate.c:393
PREDICATELOCKTARGETTAG * locktags
PREDICATELOCKTAG tag
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:256
void * palloc(Size size)
Definition: mcxt.c:950
int i
SERIALIZABLEXACT * myXact
PREDICATELOCKTARGET * myTarget
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:119

◆ GetSafeSnapshot()

static Snapshot GetSafeSnapshot ( Snapshot  snapshot)
static

Definition at line 1558 of file predicate.c.

References Assert, DEBUG2, ereport, errcode(), errmsg_internal(), 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().

1559 {
1560  Snapshot snapshot;
1561 
1563 
1564  while (true)
1565  {
1566  /*
1567  * GetSerializableTransactionSnapshotInt is going to call
1568  * GetSnapshotData, so we need to provide it the static snapshot area
1569  * our caller passed to us. The pointer returned is actually the same
1570  * one passed to it, but we avoid assuming that here.
1571  */
1572  snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
1573  NULL, InvalidPid);
1574 
1576  return snapshot; /* no concurrent r/w xacts; it's safe */
1577 
1578  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1579 
1580  /*
1581  * Wait for concurrent transactions to finish. Stop early if one of
1582  * them marked us as conflicted.
1583  */
1587  {
1588  LWLockRelease(SerializableXactHashLock);
1590  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1591  }
1593 
1595  {
1596  LWLockRelease(SerializableXactHashLock);
1597  break; /* success */
1598  }
1599 
1600  LWLockRelease(SerializableXactHashLock);
1601 
1602  /* else, need to retry... */
1603  ereport(DEBUG2,
1604  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1605  errmsg_internal("deferrable snapshot was unsafe; trying a new one")));
1606  ReleasePredicateLocks(false, false);
1607  }
1608 
1609  /*
1610  * Now we have a safe snapshot, so we don't need to do any further checks.
1611  */
1613  ReleasePredicateLocks(false, true);
1614 
1615  return snapshot;
1616 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
bool XactDeferrable
Definition: xact.c:81
int errcode(int sqlerrcode)
Definition: elog.c:694
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3332
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1762
SHM_QUEUE possibleUnsafeConflicts
#define InvalidSerializableXact
#define SXACT_FLAG_DEFERRABLE_WAITING
#define DEBUG2
Definition: elog.h:24
#define SxactIsROSafe(sxact)
Definition: predicate.c:286
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1888
bool SHMQueueEmpty(const SHM_QUEUE *queue)
Definition: shmqueue.c:180
#define ereport(elevel,...)
Definition: elog.h:155
bool XactReadOnly
Definition: xact.c:78
int errmsg_internal(const char *fmt,...)
Definition: elog.c:992
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
#define SxactIsROUnsafe(sxact)
Definition: predicate.c:287
#define InvalidPid
Definition: miscadmin.h:32

◆ GetSafeSnapshotBlockingPids()

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

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

1629 {
1630  int num_written = 0;
1631  SERIALIZABLEXACT *sxact;
1632 
1633  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1634 
1635  /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
1636  for (sxact = FirstPredXact(); sxact != NULL; sxact = NextPredXact(sxact))
1637  {
1638  if (sxact->pid == blocked_pid)
1639  break;
1640  }
1641 
1642  /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
1643  if (sxact != NULL && SxactIsDeferrableWaiting(sxact))
1644  {
1645  RWConflict possibleUnsafeConflict;
1646 
1647  /* Traverse the list of possible unsafe conflicts collecting PIDs. */
1648  possibleUnsafeConflict = (RWConflict)
1650  &sxact->possibleUnsafeConflicts,
1651  offsetof(RWConflictData, inLink));
1652 
1653  while (possibleUnsafeConflict != NULL && num_written < output_size)
1654  {
1655  output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
1656  possibleUnsafeConflict = (RWConflict)
1658  &possibleUnsafeConflict->inLink,
1659  offsetof(RWConflictData, inLink));
1660  }
1661  }
1662 
1663  LWLockRelease(SerializableXactHashLock);
1664 
1665  return num_written;
1666 }
static void output(uint64 loop_count)
struct RWConflictData * RWConflict
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
SHM_QUEUE possibleUnsafeConflicts
static SERIALIZABLEXACT * NextPredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:627
static SERIALIZABLEXACT * FirstPredXact(void)
Definition: predicate.c:612
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define SxactIsDeferrableWaiting(sxact)
Definition: predicate.c:285
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
#define offsetof(type, field)
Definition: c.h:727
SERIALIZABLEXACT * sxactOut

◆ GetSerializableTransactionSnapshot()

Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot)

Definition at line 1680 of file predicate.c.

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

Referenced by GetTransactionSnapshot().

1681 {
1683 
1684  /*
1685  * Can't use serializable mode while recovery is still active, as it is,
1686  * for example, on a hot standby. We could get here despite the check in
1687  * check_XactIsoLevel() if default_transaction_isolation is set to
1688  * serializable, so phrase the hint accordingly.
1689  */
1690  if (RecoveryInProgress())
1691  ereport(ERROR,
1692  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1693  errmsg("cannot use serializable mode in a hot standby"),
1694  errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1695  errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1696 
1697  /*
1698  * A special optimization is available for SERIALIZABLE READ ONLY
1699  * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1700  * thereby avoid all SSI overhead once it's running.
1701  */
1703  return GetSafeSnapshot(snapshot);
1704 
1705  return GetSerializableTransactionSnapshotInt(snapshot,
1706  NULL, InvalidPid);
1707 }
bool XactDeferrable
Definition: xact.c:81
int errhint(const char *fmt,...)
Definition: elog.c:1152
static Snapshot GetSafeSnapshot(Snapshot snapshot)
Definition: predicate.c:1558
int errcode(int sqlerrcode)
Definition: elog.c:694
bool RecoveryInProgress(void)
Definition: xlog.c:8132
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1762
#define ERROR
Definition: elog.h:45
int errdetail(const char *fmt,...)
Definition: elog.c:1038
#define ereport(elevel,...)
Definition: elog.h:155
bool XactReadOnly
Definition: xact.c:78
#define Assert(condition)
Definition: c.h:804
int errmsg(const char *fmt,...)
Definition: elog.c:905
#define IsolationIsSerializable()
Definition: xact.h:52
#define InvalidPid
Definition: miscadmin.h:32

◆ GetSerializableTransactionSnapshotInt()

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

Definition at line 1762 of file predicate.c.

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

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

1765 {
1766  PGPROC *proc;
1767  VirtualTransactionId vxid;
1768  SERIALIZABLEXACT *sxact,
1769  *othersxact;
1770 
1771  /* We only do this for serializable transactions. Once. */
1773 
1775 
1776  /*
1777  * Since all parts of a serializable transaction must use the same
1778  * snapshot, it is too late to establish one after a parallel operation
1779  * has begun.
1780  */
1781  if (IsInParallelMode())
1782  elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
1783 
1784  proc = MyProc;
1785  Assert(proc != NULL);
1786  GET_VXID_FROM_PGPROC(vxid, *proc);
1787 
1788  /*
1789  * First we get the sxact structure, which may involve looping and access
1790  * to the "finished" list to free a structure for use.
1791  *
1792  * We must hold SerializableXactHashLock when taking/checking the snapshot
1793  * to avoid race conditions, for much the same reasons that
1794  * GetSnapshotData takes the ProcArrayLock. Since we might have to
1795  * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
1796  * this means we have to create the sxact first, which is a bit annoying
1797  * (in particular, an elog(ERROR) in procarray.c would cause us to leak
1798  * the sxact). Consider refactoring to avoid this.
1799  */
1800 #ifdef TEST_SUMMARIZE_SERIAL
1802 #endif
1803  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1804  do
1805  {
1806  sxact = CreatePredXact();
1807  /* If null, push out committed sxact to SLRU summary & retry. */
1808  if (!sxact)
1809  {
1810  LWLockRelease(SerializableXactHashLock);
1812  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1813  }
1814  } while (!sxact);
1815 
1816  /* Get the snapshot, or check that it's safe to use */
1817  if (!sourcevxid)
1818  snapshot = GetSnapshotData(snapshot);
1819  else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid))
1820  {
1821  ReleasePredXact(sxact);
1822  LWLockRelease(SerializableXactHashLock);
1823  ereport(ERROR,
1824  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1825  errmsg("could not import the requested snapshot"),
1826  errdetail("The source process with PID %d is not running anymore.",
1827  sourcepid)));
1828  }
1829 
1830  /*
1831  * If there are no serializable transactions which are not read-only, we
1832  * can "opt out" of predicate locking and conflict checking for a
1833  * read-only transaction.
1834  *
1835  * The reason this is safe is that a read-only transaction can only become
1836  * part of a dangerous structure if it overlaps a writable transaction
1837  * which in turn overlaps a writable transaction which committed before
1838  * the read-only transaction started. A new writable transaction can
1839  * overlap this one, but it can't meet the other condition of overlapping
1840  * a transaction which committed before this one started.
1841  */
1843  {
1844  ReleasePredXact(sxact);
1845  LWLockRelease(SerializableXactHashLock);
1846  return snapshot;
1847  }
1848 
1849  /* Maintain serializable global xmin info. */
1851  {
1853  PredXact->SxactGlobalXmin = snapshot->xmin;
1855  SerialSetActiveSerXmin(snapshot->xmin);
1856  }
1857  else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
1858  {
1861  }
1862  else
1863  {
1865  }
1866 
1867  /* Initialize the structure. */
1868  sxact->vxid = vxid;
1872  SHMQueueInit(&(sxact->outConflicts));
1873  SHMQueueInit(&(sxact->inConflicts));
1875  sxact->topXid = GetTopTransactionIdIfAny();
1877  sxact->xmin = snapshot->xmin;
1878  sxact->pid = MyProcPid;
1879  SHMQueueInit(&(sxact->predicateLocks));
1880  SHMQueueElemInit(&(sxact->finishedLink));
1881  sxact->flags = 0;
1882  if (XactReadOnly)
1883  {
1884  sxact->flags |= SXACT_FLAG_READ_ONLY;
1885 
1886  /*
1887  * Register all concurrent r/w transactions as possible conflicts; if
1888  * all of them commit without any outgoing conflicts to earlier
1889  * transactions then this snapshot can be deemed safe (and we can run
1890  * without tracking predicate locks).
1891  */
1892  for (othersxact = FirstPredXact();
1893  othersxact != NULL;
1894  othersxact = NextPredXact(othersxact))
1895  {
1896  if (!SxactIsCommitted(othersxact)
1897  && !SxactIsDoomed(othersxact)
1898  && !SxactIsReadOnly(othersxact))
1899  {
1900  SetPossibleUnsafeConflict(sxact, othersxact);
1901  }
1902  }
1903  }
1904  else
1905  {
1909  }
1910 
1911  MySerializableXact = sxact;
1912  MyXactDidWrite = false; /* haven't written anything yet */
1913 
1914  LWLockRelease(SerializableXactHashLock);
1915 
1917 
1918  return snapshot;
1919 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
TransactionId finishedBefore
int MyProcPid
Definition: globals.c:41
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:81
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
PGPROC * MyProc
Definition: proc.c:68
static PredXactList PredXact
Definition: predicate.c:379
TransactionId SxactGlobalXmin
int errcode(int sqlerrcode)
Definition: elog.c:694
bool RecoveryInProgress(void)
Definition: xlog.c:8132
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
bool IsInParallelMode(void)
Definition: xact.c:1012
SHM_QUEUE possibleUnsafeConflicts
#define ERROR
Definition: elog.h:45
int max_prepared_xacts
Definition: twophase.c:117
#define InvalidSerializableXact
static void ReleasePredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:597
int MaxBackends
Definition: globals.c:137
VirtualTransactionId vxid
static SERIALIZABLEXACT * NextPredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:627
int errdetail(const char *fmt,...)
Definition: elog.c:1038
#define InvalidTransactionId
Definition: transam.h:31
TransactionId xmin
Definition: snapshot.h:157
SerCommitSeqNo lastCommitBeforeSnapshot
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:425
#define InvalidSerCommitSeqNo
static SERIALIZABLEXACT * FirstPredXact(void)
Definition: predicate.c:612
SerCommitSeqNo commitSeqNo
#define ereport(elevel,...)
Definition: elog.h:155
bool XactReadOnly
Definition: xact.c:78
#define Assert(condition)
Definition: c.h:804
SerCommitSeqNo prepareSeqNo
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:2135
SerCommitSeqNo LastSxactCommitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
void SHMQueueElemInit(SHM_QUEUE *queue)
Definition: shmqueue.c:57
int errmsg(const char *fmt,...)
Definition: elog.c:905
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
Definition: predicate.c:712
#define elog(elevel,...)
Definition: elog.h:227
#define SXACT_FLAG_READ_ONLY
static void SerialSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:1018
static void SummarizeOldestCommittedSxact(void)
Definition: predicate.c:1501
static bool MyXactDidWrite
Definition: predicate.c:417
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1922
#define TransactionIdIsValid(xid)
Definition: transam.h:41
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition: procarray.c:2498
Definition: proc.h:121
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:580
#define SxactIsCommitted(sxact)
Definition: predicate.c:272
union SERIALIZABLEXACT::@105 SeqNo

◆ InitPredicateLocks()

void InitPredicateLocks ( void  )

Definition at line 1153 of file predicate.c.

References PredXactListData::activeList, Assert, PredXactListData::availableList, RWConflictPoolHeaderData::availableList, PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, CreatePredXact(), PredXactListData::element, RWConflictPoolHeaderData::element, HASHCTL::entrysize, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FirstNormalSerCommitSeqNo, SERIALIZABLEXACT::flags, HASHCTL::hash, HASH_BLOBS, HASH_ELEM, HASH_ENTER, HASH_FIXED_SIZE, HASH_FUNCTION, HASH_PARTITION, hash_search(), PredXactListData::HavePartialClearedThrough, i, SERIALIZABLEXACT::inConflicts, InvalidTransactionId, IsUnderPostmaster, HASHCTL::keysize, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, PredXactListElementData::link, LWLockInitialize(), LWTRANCHE_PER_XACT_PREDICATE_LIST, max_prepared_xacts, MaxBackends, mul_size(), NPREDICATELOCKTARGETENTS, HASHCTL::num_partitions, NUM_PREDICATELOCK_PARTITIONS, PredXactListData::OldCommittedSxact, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::perXactPredicateListLock, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, predicatelock_hash(), PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, PredXactListDataSize, PredXactListElementDataSize, SERIALIZABLEXACT::prepareSeqNo, RWConflictDataSize, RWConflictPoolHeaderDataSize, ScratchTargetTagHash, SERIALIZABLEXACT::SeqNo, SerialInit(), SetInvalidVirtualTransactionId, ShmemAlloc(), ShmemInitHash(), ShmemInitStruct(), SHMQueueInit(), SHMQueueInsertBefore(), PredXactListElementData::sxact, SXACT_FLAG_COMMITTED, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SERIALIZABLEXACT::topXid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, and SERIALIZABLEXACT::xmin.

Referenced by CreateSharedMemoryAndSemaphores().

1154 {
1155  HASHCTL info;
1156  long max_table_size;
1157  Size requestSize;
1158  bool found;
1159 
1160 #ifndef EXEC_BACKEND
1162 #endif
1163 
1164  /*
1165  * Compute size of predicate lock target hashtable. Note these
1166  * calculations must agree with PredicateLockShmemSize!
1167  */
1168  max_table_size = NPREDICATELOCKTARGETENTS();
1169 
1170  /*
1171  * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1172  * per-predicate-lock-target information.
1173  */
1174  info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1175  info.entrysize = sizeof(PREDICATELOCKTARGET);
1177 
1178  PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1179  max_table_size,
1180  max_table_size,
1181  &info,
1182  HASH_ELEM | HASH_BLOBS |
1184 
1185  /*
1186  * Reserve a dummy entry in the hash table; we use it to make sure there's
1187  * always one entry available when we need to split or combine a page,
1188  * because running out of space there could mean aborting a
1189  * non-serializable transaction.
1190  */
1191  if (!IsUnderPostmaster)
1192  {
1194  HASH_ENTER, &found);
1195  Assert(!found);
1196  }
1197 
1198  /* Pre-calculate the hash and partition lock of the scratch entry */
1201 
1202  /*
1203  * Allocate hash table for PREDICATELOCK structs. This stores per
1204  * xact-lock-of-a-target information.
1205  */
1206  info.keysize = sizeof(PREDICATELOCKTAG);
1207  info.entrysize = sizeof(PREDICATELOCK);
1208  info.hash = predicatelock_hash;
1210 
1211  /* Assume an average of 2 xacts per target */
1212  max_table_size *= 2;
1213 
1214  PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1215  max_table_size,
1216  max_table_size,
1217  &info,
1220 
1221  /*
1222  * Compute size for serializable transaction hashtable. Note these
1223  * calculations must agree with PredicateLockShmemSize!
1224  */
1225  max_table_size = (MaxBackends + max_prepared_xacts);
1226 
1227  /*
1228  * Allocate a list to hold information on transactions participating in
1229  * predicate locking.
1230  *
1231  * Assume an average of 10 predicate locking transactions per backend.
1232  * This allows aggressive cleanup while detail is present before data must
1233  * be summarized for storage in SLRU and the "dummy" transaction.
1234  */
1235  max_table_size *= 10;
1236 
1237  PredXact = ShmemInitStruct("PredXactList",
1239  &found);
1240  Assert(found == IsUnderPostmaster);
1241  if (!found)
1242  {
1243  int i;
1244 
1253  requestSize = mul_size((Size) max_table_size,
1255  PredXact->element = ShmemAlloc(requestSize);
1256  /* Add all elements to available list, clean. */
1257  memset(PredXact->element, 0, requestSize);
1258  for (i = 0; i < max_table_size; i++)
1259  {
1263  &(PredXact->element[i].link));
1264  }
1280  }
1281  /* This never changes, so let's keep a local copy. */
1283 
1284  /*
1285  * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1286  * information for serializable transactions which have accessed data.
1287  */
1288  info.keysize = sizeof(SERIALIZABLEXIDTAG);
1289  info.entrysize = sizeof(SERIALIZABLEXID);
1290 
1291  SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1292  max_table_size,
1293  max_table_size,
1294  &info,
1295  HASH_ELEM | HASH_BLOBS |
1296  HASH_FIXED_SIZE);
1297 
1298  /*
1299  * Allocate space for tracking rw-conflicts in lists attached to the
1300  * transactions.
1301  *
1302  * Assume an average of 5 conflicts per transaction. Calculations suggest
1303  * that this will prevent resource exhaustion in even the most pessimal
1304  * loads up to max_connections = 200 with all 200 connections pounding the
1305  * database with serializable transactions. Beyond that, there may be
1306  * occasional transactions canceled when trying to flag conflicts. That's
1307  * probably OK.
1308  */
1309  max_table_size *= 5;
1310 
1311  RWConflictPool = ShmemInitStruct("RWConflictPool",
1313  &found);
1314  Assert(found == IsUnderPostmaster);
1315  if (!found)
1316  {
1317  int i;
1318 
1320  requestSize = mul_size((Size) max_table_size,
1322  RWConflictPool->element = ShmemAlloc(requestSize);
1323  /* Add all elements to available list, clean. */
1324  memset(RWConflictPool->element, 0, requestSize);
1325  for (i = 0; i < max_table_size; i++)
1326  {
1328  &(RWConflictPool->element[i].outLink));
1329  }
1330  }
1331 
1332  /*
1333  * Create or attach to the header for the list of finished serializable
1334  * transactions.
1335  */
1337  ShmemInitStruct("FinishedSerializableTransactions",
1338  sizeof(SHM_QUEUE),
1339  &found);
1340  Assert(found == IsUnderPostmaster);
1341  if (!found)
1343 
1344  /*
1345  * Initialize the SLRU storage for old committed serializable
1346  * transactions.
1347  */
1348  SerialInit();
1349 }
TransactionId finishedBefore
#define PredXactListDataSize
struct SERIALIZABLEXID SERIALIZABLEXID
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
#define HASH_ELEM
Definition: hsearch.h:95
static void SerialInit(void)
Definition: predicate.c:866
#define NPREDICATELOCKTARGETENTS()
Definition: predicate.c:259
static PredXactList PredXact
Definition: predicate.c:379
TransactionId SxactGlobalXmin
struct SERIALIZABLEXIDTAG SERIALIZABLEXIDTAG
struct PREDICATELOCKTARGET PREDICATELOCKTARGET
Size entrysize
Definition: hsearch.h:76
static uint32 predicatelock_hash(const void *key, Size keysize)
Definition: predicate.c:1417
static HTAB * SerializableXidHash
Definition: predicate.c:391
void * ShmemAlloc(Size size)
Definition: shmem.c:161
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
#define SXACT_FLAG_COMMITTED
#define FirstNormalSerCommitSeqNo
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
#define HASH_PARTITION
Definition: hsearch.h:92
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
SHM_QUEUE possibleUnsafeConflicts
static HTAB * PredicateLockHash
Definition: predicate.c:393
int max_prepared_xacts
Definition: twophase.c:117
static RWConflictPoolHeader RWConflictPool
Definition: predicate.c:385
struct PREDICATELOCK PREDICATELOCK
long num_partitions
Definition: hsearch.h:68
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
struct PREDICATELOCKTAG PREDICATELOCKTAG
int MaxBackends
Definition: globals.c:137
#define RWConflictDataSize
VirtualTransactionId vxid
bool IsUnderPostmaster
Definition: globals.c:110
#define InvalidTransactionId
Definition: transam.h:31
SerCommitSeqNo lastCommitBeforeSnapshot
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:743
SerCommitSeqNo commitSeqNo
#define RWConflictPoolHeaderDataSize
SerCommitSeqNo HavePartialClearedThrough
#define HASH_BLOBS
Definition: hsearch.h:97
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
SerCommitSeqNo CanPartialClearThrough
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
Size keysize
Definition: hsearch.h:75
#define Assert(condition)
Definition: c.h:804
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:78
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
SerCommitSeqNo prepareSeqNo
size_t Size
Definition: c.h:540
SerCommitSeqNo LastSxactCommitSeqNo
SERIALIZABLEXACT * OldCommittedSxact
#define HASH_FIXED_SIZE
Definition: hsearch.h:105
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:357
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
int i
static const PREDICATELOCKTARGETTAG ScratchTargetTag
Definition: predicate.c:401
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:341
static SHM_QUEUE * FinishedSerializableTransactions
Definition: predicate.c:394
static uint32 ScratchTargetTagHash
Definition: predicate.c:402
static LWLock * ScratchPartitionLock
Definition: predicate.c:403
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:580
PredXactListElement element
#define PredXactListElementDataSize
HashValueFunc hash
Definition: hsearch.h:78
#define HASH_FUNCTION
Definition: hsearch.h:98
union SERIALIZABLEXACT::@105 SeqNo
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:119

◆ MaxPredicateChildLocks()

static int MaxPredicateChildLocks ( const PREDICATELOCKTARGETTAG tag)
static

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

2282 {
2283  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2284  {
2285  case PREDLOCKTAG_RELATION:
2290 
2291  case PREDLOCKTAG_PAGE:
2293 
2294  case PREDLOCKTAG_TUPLE:
2295 
2296  /*
2297  * not reachable: nothing is finer-granularity than a tuple, so we
2298  * should never try to promote to it.
2299  */
2300  Assert(false);
2301  return 0;
2302  }
2303 
2304  /* not reachable */
2305  Assert(false);
2306  return 0;
2307 }
int max_predicate_locks_per_xact
Definition: predicate.c:366
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define Assert(condition)
Definition: c.h:804
int max_predicate_locks_per_relation
Definition: predicate.c:367
int max_predicate_locks_per_page
Definition: predicate.c:368

◆ NextPredXact()

static SERIALIZABLEXACT * NextPredXact ( SERIALIZABLEXACT sxact)
static

Definition at line 627 of file predicate.c.

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

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

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

◆ OnConflict_CheckForSerializationFailure()

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

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

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

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

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

1991 {
1992  PREDICATELOCKTARGETTAG targettag;
1993  uint32 targettaghash;
1994  LWLock *partitionLock;
1995  PREDICATELOCKTARGET *target;
1996 
1998  relation->rd_node.dbNode,
1999  relation->rd_id,
2000  blkno);
2001 
2002  targettaghash = PredicateLockTargetTagHashCode(&targettag);
2003  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2004  LWLockAcquire(partitionLock, LW_SHARED);
2005  target = (PREDICATELOCKTARGET *)
2007  &targettag, targettaghash,
2008  HASH_FIND, NULL);
2009  LWLockRelease(partitionLock);
2010 
2011  return (target != NULL);
2012 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:967
Definition: lwlock.h:31
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
unsigned int uint32
Definition: c.h:441
Oid rd_id
Definition: rel.h:112
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
RelFileNode rd_node
Definition: rel.h:55
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206

◆ PostPrepare_PredicateLocks()

void PostPrepare_PredicateLocks ( TransactionId  xid)

Definition at line 5001 of file predicate.c.

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

Referenced by PrepareTransaction().

5002 {
5004  return;
5005 
5007 
5008  MySerializableXact->pid = 0;
5009 
5011  LocalPredicateLockHash = NULL;
5012 
5014  MyXactDidWrite = false;
5015 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:862
#define SxactIsPrepared(sxact)
Definition: predicate.c:273
#define InvalidSerializableXact
#define Assert(condition)
Definition: c.h:804
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409
static bool MyXactDidWrite
Definition: predicate.c:417

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4831 of file predicate.c.

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

Referenced by CommitTransaction(), and PrepareTransaction().

4832 {
4833  RWConflict nearConflict;
4834 
4836  return;
4837 
4839 
4840  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4841 
4842  /* Check if someone else has already decided that we need to die */
4844  {
4846  LWLockRelease(SerializableXactHashLock);
4847  ereport(ERROR,
4848  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4849  errmsg("could not serialize access due to read/write dependencies among transactions"),
4850  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4851  errhint("The transaction might succeed if retried.")));
4852  }
4853 
4854  nearConflict = (RWConflict)
4857  offsetof(RWConflictData, inLink));
4858  while (nearConflict)
4859  {
4860  if (!SxactIsCommitted(nearConflict->sxactOut)
4861  && !SxactIsDoomed(nearConflict->sxactOut))
4862  {
4863  RWConflict farConflict;
4864 
4865  farConflict = (RWConflict)
4866  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4867  &nearConflict->sxactOut->inConflicts,
4868  offsetof(RWConflictData, inLink));
4869  while (farConflict)
4870  {
4871  if (farConflict->sxactOut == MySerializableXact
4872  || (!SxactIsCommitted(farConflict->sxactOut)
4873  && !SxactIsReadOnly(farConflict->sxactOut)
4874  && !SxactIsDoomed(farConflict->sxactOut)))
4875  {
4876  /*
4877  * Normally, we kill the pivot transaction to make sure we
4878  * make progress if the failing transaction is retried.
4879  * However, we can't kill it if it's already prepared, so
4880  * in that case we commit suicide instead.
4881  */
4882  if (SxactIsPrepared(nearConflict->sxactOut))
4883  {
4884  LWLockRelease(SerializableXactHashLock);
4885  ereport(ERROR,
4886  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4887  errmsg("could not serialize access due to read/write dependencies among transactions"),
4888  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4889  errhint("The transaction might succeed if retried.")));
4890  }
4891  nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4892  break;
4893  }
4894  farConflict = (RWConflict)
4895  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4896  &farConflict->inLink,
4897  offsetof(RWConflictData, inLink));
4898  }
4899  }
4900 
4901  nearConflict = (RWConflict)
4903  &nearConflict->inLink,
4904  offsetof(RWConflictData, inLink));
4905  }
4906 
4909 
4910  LWLockRelease(SerializableXactHashLock);
4911 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
int errhint(const char *fmt,...)
Definition: elog.c:1152
static PredXactList PredXact
Definition: predicate.c:379
struct RWConflictData * RWConflict
int errcode(int sqlerrcode)
Definition: elog.c:694
#define SxactIsPrepared(sxact)
Definition: predicate.c:273
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1065
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define ERROR
Definition: elog.h:45
#define InvalidSerializableXact
#define SXACT_FLAG_PREPARED
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define ereport(elevel,...)
Definition: elog.h:155
#define SXACT_FLAG_DOOMED
#define Assert(condition)
Definition: c.h:804
SerCommitSeqNo prepareSeqNo
SerCommitSeqNo LastSxactCommitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
#define SxactIsPartiallyReleased(sxact)
Definition: predicate.c:288
int errmsg(const char *fmt,...)
Definition: elog.c:905
#define IsolationIsSerializable()
Definition: xact.h:52
#define SxactIsCommitted(sxact)
Definition: predicate.c:272
#define offsetof(type, field)
Definition: c.h:727
SERIALIZABLEXACT * sxactOut

◆ predicatelock_hash()

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

Definition at line 1417 of file predicate.c.

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

Referenced by InitPredicateLocks().

1418 {
1419  const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
1420  uint32 targethash;
1421 
1422  Assert(keysize == sizeof(PREDICATELOCKTAG));
1423 
1424  /* Look into the associated target object, and compute its hash code */
1425  targethash = PredicateLockTargetTagHashCode(&predicatelocktag->myTarget->tag);
1426 
1427  return PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash);
1428 }
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
unsigned int uint32
Definition: c.h:441
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:804
PREDICATELOCKTARGET * myTarget

◆ predicatelock_twophase_recover()

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

Definition at line 5050 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, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, SERIALIZABLEXACT::prepareSeqNo, RecoverySerCommitSeqNo, SERIALIZABLEXACT::SeqNo, SerialSetActiveSerXmin(), 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.

5052 {
5053  TwoPhasePredicateRecord *record;
5054 
5055  Assert(len == sizeof(TwoPhasePredicateRecord));
5056 
5057  record = (TwoPhasePredicateRecord *) recdata;
5058 
5059  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
5060  (record->type == TWOPHASEPREDICATERECORD_LOCK));
5061 
5062  if (record->type == TWOPHASEPREDICATERECORD_XACT)
5063  {
5064  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
5065  TwoPhasePredicateXactRecord *xactRecord;
5066  SERIALIZABLEXACT *sxact;
5067  SERIALIZABLEXID *sxid;
5068  SERIALIZABLEXIDTAG sxidtag;
5069  bool found;
5070 
5071  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
5072 
5073  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
5074  sxact = CreatePredXact();
5075  if (!sxact)
5076  ereport(ERROR,
5077  (errcode(ERRCODE_OUT_OF_MEMORY),
5078  errmsg("out of shared memory")));
5079 
5080  /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
5081  sxact->vxid.backendId = InvalidBackendId;
5083  sxact->pid = 0;
5084 
5085  /* a prepared xact hasn't committed yet */
5089 
5091 
5092  /*
5093  * Don't need to track this; no transactions running at the time the
5094  * recovered xact started are still active, except possibly other
5095  * prepared xacts and we don't care whether those are RO_SAFE or not.
5096  */
5098 
5099  SHMQueueInit(&(sxact->predicateLocks));
5100  SHMQueueElemInit(&(sxact->finishedLink));
5101 
5102  sxact->topXid = xid;
5103  sxact->xmin = xactRecord->xmin;
5104  sxact->flags = xactRecord->flags;
5105  Assert(SxactIsPrepared(sxact));
5106  if (!SxactIsReadOnly(sxact))
5107  {
5111  }
5112 
5113  /*
5114  * We don't know whether the transaction had any conflicts or not, so
5115  * we'll conservatively assume that it had both a conflict in and a
5116  * conflict out, and represent that with the summary conflict flags.
5117  */
5118  SHMQueueInit(&(sxact->outConflicts));
5119  SHMQueueInit(&(sxact->inConflicts));
5122 
5123  /* Register the transaction's xid */
5124  sxidtag.xid = xid;
5126  &sxidtag,
5127  HASH_ENTER, &found);
5128  Assert(sxid != NULL);
5129  Assert(!found);
5130  sxid->myXact = (SERIALIZABLEXACT *) sxact;
5131 
5132  /*
5133  * Update global xmin. Note that this is a special case compared to
5134  * registering a normal transaction, because the global xmin might go
5135  * backwards. That's OK, because until recovery is over we're not
5136  * going to complete any transactions or create any non-prepared
5137  * transactions, so there's no danger of throwing away.
5138  */
5141  {
5142  PredXact->SxactGlobalXmin = sxact->xmin;
5144  SerialSetActiveSerXmin(sxact->xmin);
5145  }
5146  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
5147  {
5150  }
5151 
5152  LWLockRelease(SerializableXactHashLock);
5153  }
5154  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
5155  {
5156  /* Lock record. Recreate the PREDICATELOCK */
5157  TwoPhasePredicateLockRecord *lockRecord;
5158  SERIALIZABLEXID *sxid;
5159  SERIALIZABLEXACT *sxact;
5160  SERIALIZABLEXIDTAG sxidtag;
5161  uint32 targettaghash;
5162 
5163  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
5164  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
5165 
5166  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
5167  sxidtag.xid = xid;
5168  sxid = (SERIALIZABLEXID *)
5169  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
5170  LWLockRelease(SerializableXactHashLock);
5171 
5172  Assert(sxid != NULL);
5173  sxact = sxid->myXact;
5174  Assert(sxact != InvalidSerializableXact);
5175 
5176  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5177  }
5178 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
TransactionId finishedBefore
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2445
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
static PredXactList PredXact
Definition: predicate.c:379
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
TransactionId SxactGlobalXmin
int errcode(int sqlerrcode)
Definition: elog.c:694
static HTAB * SerializableXidHash
Definition: predicate.c:391
SERIALIZABLEXACT * myXact
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
#define SxactIsPrepared(sxact)
Definition: predicate.c:273
TwoPhasePredicateRecordType type
LocalTransactionId localTransactionId
Definition: lock.h:66
PREDICATELOCKTARGETTAG target
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
SHM_QUEUE possibleUnsafeConflicts
#define ERROR
Definition: elog.h:45
int max_prepared_xacts
Definition: twophase.c:117
TwoPhasePredicateXactRecord xactRecord
#define InvalidSerializableXact
int MaxBackends
Definition: globals.c:137
VirtualTransactionId vxid
#define InvalidTransactionId
Definition: transam.h:31
unsigned int uint32
Definition: c.h:441
uint32 LocalTransactionId
Definition: c.h:589
SerCommitSeqNo lastCommitBeforeSnapshot
#define InvalidSerCommitSeqNo
SerCommitSeqNo commitSeqNo
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
#define InvalidBackendId
Definition: backendid.h:23
#define ereport(elevel,...)
Definition: elog.h:155
#define RecoverySerCommitSeqNo
#define Assert(condition)
Definition: c.h:804
BackendId backendId
Definition: lock.h:65
SerCommitSeqNo prepareSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
void SHMQueueElemInit(SHM_QUEUE *queue)
Definition: shmqueue.c:57
int errmsg(const char *fmt,...)
Definition: elog.c:905
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
static void SerialSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:1018
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TwoPhasePredicateLockRecord lockRecord
#define SXACT_FLAG_SUMMARY_CONFLICT_IN
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:580
union TwoPhasePredicateRecord::@106 data
union SERIALIZABLEXACT::@105 SeqNo

◆ PredicateLockAcquire()

static void PredicateLockAcquire ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2510 of file predicate.c.

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

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

2511 {
2512  uint32 targettaghash;
2513  bool found;
2514  LOCALPREDICATELOCK *locallock;
2515 
2516  /* Do we have the lock already, or a covering lock? */
2517  if (PredicateLockExists(targettag))
2518  return;
2519 
2520  if (CoarserLockCovers(targettag))
2521  return;
2522 
2523  /* the same hash and LW lock apply to the lock target and the local lock. */
2524  targettaghash = PredicateLockTargetTagHashCode(targettag);
2525 
2526  /* Acquire lock in local table */
2527  locallock = (LOCALPREDICATELOCK *)
2529  targettag, targettaghash,
2530  HASH_ENTER, &found);
2531  locallock->held = true;
2532  if (!found)
2533  locallock->childLocks = 0;
2534 
2535  /* Actually create the lock */
2536  CreatePredicateLock(targettag, targettaghash, MySerializableXact);
2537 
2538  /*
2539  * Lock has been acquired. Check whether it should be promoted to a
2540  * coarser granularity, or whether there are finer-granularity locks to
2541  * clean up.
2542  */
2543  if (CheckAndPromotePredicateLockRequest(targettag))
2544  {
2545  /*
2546  * Lock request was promoted to a coarser-granularity lock, and that
2547  * lock was acquired. It will delete this lock and any of its
2548  * children, so we're done.
2549  */
2550  }
2551  else
2552  {
2553  /* Clean up any finer-granularity locks */
2555  DeleteChildTargetLocks(targettag);
2556  }
2557 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:967
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2445
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2027
static void DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
Definition: predicate.c:2196
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
unsigned int uint32
Definition: c.h:441
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
static bool CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag)
Definition: predicate.c:2318
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409
static bool CoarserLockCovers(const PREDICATELOCKTARGETTAG *newtargettag)
Definition: predicate.c:2093

◆ PredicateLockExists()

static bool PredicateLockExists ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2027 of file predicate.c.

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

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

2028 {
2029  LOCALPREDICATELOCK *lock;
2030 
2031  /* check local hash table */
2033  targettag,
2034  HASH_FIND, NULL);
2035 
2036  if (!lock)
2037  return false;
2038 
2039  /*
2040  * Found entry in the table, but still need to check whether it's actually
2041  * held -- it could just be a parent of some held lock.
2042  */
2043  return lock->held;
2044 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409

◆ PredicateLockingNeededForRelation()

static bool PredicateLockingNeededForRelation ( Relation  relation)
inlinestatic

Definition at line 495 of file predicate.c.

References FirstBootstrapObjectId, RelationData::rd_id, RelationData::rd_rel, and RelationUsesLocalBuffers.

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

496 {
497  return !(relation->rd_id < FirstBootstrapObjectId ||
498  RelationUsesLocalBuffers(relation) ||
499  relation->rd_rel->relkind == RELKIND_MATVIEW);
500 }
Form_pg_class rd_rel
Definition: rel.h:110
#define FirstBootstrapObjectId
Definition: transam.h:189
Oid rd_id
Definition: rel.h:112
#define RelationUsesLocalBuffers(relation)
Definition: rel.h:573

◆ PredicateLockPage()

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

Definition at line 2592 of file predicate.c.

References RelFileNode::dbNode, PredicateLockAcquire(), RelationData::rd_id, RelationData::rd_node, SerializationNeededForRead(), and SET_PREDICATELOCKTARGETTAG_PAGE.

Referenced by _bt_endpoint(), _bt_first(), _bt_readnextpage(), _hash_first(), _hash_readnext(), collectMatchBitmap(), gistScanPage(), IndexOnlyNext(), moveRightIfItNeeded(), scanPendingInsert(), and startScanEntry().

2593 {
2595 
2596  if (!SerializationNeededForRead(relation, snapshot))
2597  return;
2598 
2600  relation->rd_node.dbNode,
2601  relation->rd_id,
2602  blkno);
2603  PredicateLockAcquire(&tag);
2604 }
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2510
Oid rd_id
Definition: rel.h:112
RelFileNode rd_node
Definition: rel.h:55
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:514

◆ PredicateLockPageCombine()

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

Definition at line 3252 of file predicate.c.

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

3254 {
3255  /*
3256  * Page combines differ from page splits in that we ought to be able to
3257  * remove the locks on the old page after transferring them to the new
3258  * page, instead of duplicating them. However, because we can't edit other
3259  * backends' local lock tables, removing the old lock would leave them
3260  * with an entry in their LocalPredicateLockHash for a lock they're not
3261  * holding, which isn't acceptable. So we wind up having to do the same
3262  * work as a page split, acquiring a lock on the new page and keeping the
3263  * old page locked too. That can lead to some false positives, but should
3264  * be rare in practice.
3265  */
3266  PredicateLockPageSplit(relation, oldblkno, newblkno);
3267 }
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3167

◆ PredicateLockPageSplit()

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

Definition at line 3167 of file predicate.c.

References Assert, BlockNumberIsValid, RelFileNode::dbNode, GetParentPredicateLockTag(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PredicateLockingNeededForRelation(), RelationData::rd_id, RelationData::rd_node, SET_PREDICATELOCKTARGETTAG_PAGE, success, PredXactListData::SxactGlobalXmin, TransactionIdIsValid, and TransferPredicateLocksToNewTarget().

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

3169 {
3170  PREDICATELOCKTARGETTAG oldtargettag;
3171  PREDICATELOCKTARGETTAG newtargettag;
3172  bool success;
3173 
3174  /*
3175  * Bail out quickly if there are no serializable transactions running.
3176  *
3177  * It's safe to do this check without taking any additional locks. Even if
3178  * a serializable transaction starts concurrently, we know it can't take
3179  * any SIREAD locks on the page being split because the caller is holding
3180  * the associated buffer page lock. Memory reordering isn't an issue; the
3181  * memory barrier in the LWLock acquisition guarantees that this read
3182  * occurs while the buffer page lock is held.
3183  */
3185  return;
3186 
3187  if (!PredicateLockingNeededForRelation(relation))
3188  return;
3189 
3190  Assert(oldblkno != newblkno);
3191  Assert(BlockNumberIsValid(oldblkno));
3192  Assert(BlockNumberIsValid(newblkno));
3193 
3194  SET_PREDICATELOCKTARGETTAG_PAGE(oldtargettag,
3195  relation->rd_node.dbNode,
3196  relation->rd_id,
3197  oldblkno);
3198  SET_PREDICATELOCKTARGETTAG_PAGE(newtargettag,
3199  relation->rd_node.dbNode,
3200  relation->rd_id,
3201  newblkno);
3202 
3203  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
3204 
3205  /*
3206  * Try copying the locks over to the new page's tag, creating it if
3207  * necessary.
3208  */
3209  success = TransferPredicateLocksToNewTarget(oldtargettag,
3210  newtargettag,
3211  false);
3212 
3213  if (!success)
3214  {
3215  /*
3216  * No more predicate lock entries are available. Failure isn't an
3217  * option here, so promote the page lock to a relation lock.
3218  */
3219 
3220  /* Get the parent relation lock's lock tag */
3221  success = GetParentPredicateLockTag(&oldtargettag,
3222  &newtargettag);
3223  Assert(success);
3224 
3225  /*
3226  * Move the locks to the parent. This shouldn't fail.
3227  *
3228  * Note that here we are removing locks held by other backends,
3229  * leading to a possible inconsistency in their local lock hash table.
3230  * This is OK because we're replacing it with a lock that covers the
3231  * old one.
3232  */
3233  success = TransferPredicateLocksToNewTarget(oldtargettag,
3234  newtargettag,
3235  true);
3236  Assert(success);
3237  }
3238 
3239  LWLockRelease(SerializablePredicateListLock);
3240 }
static bool PredicateLockingNeededForRelation(Relation relation)
Definition: predicate.c:495
static bool TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag, PREDICATELOCKTARGETTAG newtargettag, bool removeOld)
Definition: predicate.c:2733
static PredXactList P