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 p, int q)
 
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.

◆ 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.

Referenced by SerialPagePrecedesLogically().

◆ 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:429
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 4854 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().

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

◆ AttachSerializableXact()

void AttachSerializableXact ( SerializableXactHandle  handle)

Definition at line 5124 of file predicate.c.

References Assert, CreateLocalPredicateLockHash(), and InvalidSerializableXact.

Referenced by ParallelWorkerMain().

5125 {
5126 
5128 
5129  MySerializableXact = (SERIALIZABLEXACT *) handle;
5132 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
#define InvalidSerializableXact
#define Assert(condition)
Definition: c.h:800
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1850

◆ CheckAndPromotePredicateLockRequest()

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2247 of file predicate.c.

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

Referenced by PredicateLockAcquire().

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

◆ CheckForSerializableConflictIn()

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

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

4376 {
4377  PREDICATELOCKTARGETTAG targettag;
4378 
4379  if (!SerializationNeededForWrite(relation))
4380  return;
4381 
4382  /* Check if someone else has already decided that we need to die */
4384  ereport(ERROR,
4385  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4386  errmsg("could not serialize access due to read/write dependencies among transactions"),
4387  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4388  errhint("The transaction might succeed if retried.")));
4389 
4390  /*
4391  * We're doing a write which might cause rw-conflicts now or later.
4392  * Memorize that fact.
4393  */
4394  MyXactDidWrite = true;
4395 
4396  /*
4397  * It is important that we check for locks from the finest granularity to
4398  * the coarsest granularity, so that granularity promotion doesn't cause
4399  * us to miss a lock. The new (coarser) lock will be acquired before the
4400  * old (finer) locks are released.
4401  *
4402  * It is not possible to take and hold a lock across the checks for all
4403  * granularities because each target could be in a separate partition.
4404  */
4405  if (tid != NULL)
4406  {
4408  relation->rd_node.dbNode,
4409  relation->rd_id,
4412  CheckTargetForConflictsIn(&targettag);
4413  }
4414 
4415  if (blkno != InvalidBlockNumber)
4416  {
4418  relation->rd_node.dbNode,
4419  relation->rd_id,
4420  blkno);
4421  CheckTargetForConflictsIn(&targettag);
4422  }
4423 
4425  relation->rd_node.dbNode,
4426  relation->rd_id);
4427  CheckTargetForConflictsIn(&targettag);
4428 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
int errhint(const char *fmt,...)
Definition: elog.c:1149
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4193
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
int errcode(int sqlerrcode)
Definition: elog.c:691
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:1062
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define ERROR
Definition: elog.h:43
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:902
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 4050 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().

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

◆ CheckForSerializableConflictOutNeeded()

bool CheckForSerializableConflictOutNeeded ( Relation  relation,
Snapshot  snapshot 
)

Definition at line 4018 of file predicate.c.

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

Referenced by HeapCheckForSerializableConflictOut().

4019 {
4020  if (!SerializationNeededForRead(relation, snapshot))
4021  return false;
4022 
4023  /* Check if someone else has already decided that we need to die */
4025  {
4026  ereport(ERROR,
4027  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4028  errmsg("could not serialize access due to read/write dependencies among transactions"),
4029  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4030  errhint("The transaction might succeed if retried.")));
4031  }
4032 
4033  return true;
4034 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
int errhint(const char *fmt,...)
Definition: elog.c:1149
int errcode(int sqlerrcode)
Definition: elog.c:691
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1062
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#define ERROR
Definition: elog.h:43
#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:902

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 1013 of file predicate.c.

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

Referenced by CheckPointGuts().

1014 {
1015  int tailPage;
1016 
1017  LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
1018 
1019  /* Exit quickly if the SLRU is currently not in use. */
1020  if (serialControl->headPage < 0)
1021  {
1022  LWLockRelease(SerialSLRULock);
1023  return;
1024  }
1025 
1027  {
1028  /* We can truncate the SLRU up to the page containing tailXid */
1029  tailPage = SerialPage(serialControl->tailXid);
1030  }
1031  else
1032  {
1033  /*
1034  * The SLRU is no longer needed. Truncate to head before we set head
1035  * invalid.
1036  *
1037  * XXX: It's possible that the SLRU is not needed again until XID
1038  * wrap-around has happened, so that the segment containing headPage
1039  * that we leave behind will appear to be new again. In that case it
1040  * won't be removed until XID horizon advances enough to make it
1041  * current again.
1042  */
1043  tailPage = serialControl->headPage;
1044  serialControl->headPage = -1;
1045  }
1046 
1047  LWLockRelease(SerialSLRULock);
1048 
1049  /* Truncate away pages that are no longer required */
1050  SimpleLruTruncate(SerialSlruCtl, tailPage);
1051 
1052  /*
1053  * Write dirty SLRU pages to disk
1054  *
1055  * This is not actually necessary from a correctness point of view. We do
1056  * it merely as a debugging aid.
1057  *
1058  * We're doing this after the truncation to avoid writing pages right
1059  * before deleting the file in which they sit, which would be completely
1060  * pointless.
1061  */
1063 }
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1225
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
#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:1207
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 4458 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().

4459 {
4460  HASH_SEQ_STATUS seqstat;
4461  PREDICATELOCKTARGET *target;
4462  Oid dbId;
4463  Oid heapId;
4464  int i;
4465 
4466  /*
4467  * Bail out quickly if there are no serializable transactions running.
4468  * It's safe to check this without taking locks because the caller is
4469  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4470  * would matter here can be acquired while that is held.
4471  */
4473  return;
4474 
4475  if (!SerializationNeededForWrite(relation))
4476  return;
4477 
4478  /*
4479  * We're doing a write which might cause rw-conflicts now or later.
4480  * Memorize that fact.
4481  */
4482  MyXactDidWrite = true;
4483 
4484  Assert(relation->rd_index == NULL); /* not an index relation */
4485 
4486  dbId = relation->rd_node.dbNode;
4487  heapId = relation->rd_id;
4488 
4489  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
4490  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4492  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4493 
4494  /* Scan through target list */
4496 
4497  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4498  {
4499  PREDICATELOCK *predlock;
4500 
4501  /*
4502  * Check whether this is a target which needs attention.
4503  */
4504  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4505  continue; /* wrong relation id */
4506  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4507  continue; /* wrong database id */
4508 
4509  /*
4510  * Loop through locks for this target and flag conflicts.
4511  */
4512  predlock = (PREDICATELOCK *)
4513  SHMQueueNext(&(target->predicateLocks),
4514  &(target->predicateLocks),
4515  offsetof(PREDICATELOCK, targetLink));
4516  while (predlock)
4517  {
4518  PREDICATELOCK *nextpredlock;
4519 
4520  nextpredlock = (PREDICATELOCK *)
4521  SHMQueueNext(&(target->predicateLocks),
4522  &(predlock->targetLink),
4523  offsetof(PREDICATELOCK, targetLink));
4524 
4525  if (predlock->tag.myXact != MySerializableXact
4527  {
4529  }
4530 
4531  predlock = nextpredlock;
4532  }
4533  }
4534 
4535  /* Release locks in reverse order */
4536  LWLockRelease(SerializableXactHashLock);
4537  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4539  LWLockRelease(SerializablePredicateListLock);
4540 }
#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:4550
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:1811
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:800
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
#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:723
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:119

◆ CheckTargetForConflictsIn()

static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag)
static

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

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

◆ ClearOldPredicateLocks()

static void ClearOldPredicateLocks ( void  )
static

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

3673 {
3674  SERIALIZABLEXACT *finishedSxact;
3675  PREDICATELOCK *predlock;
3676 
3677  /*
3678  * Loop through finished transactions. They are in commit order, so we can
3679  * stop as soon as we find one that's still interesting.
3680  */
3681  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3682  finishedSxact = (SERIALIZABLEXACT *)
3685  offsetof(SERIALIZABLEXACT, finishedLink));
3686  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3687  while (finishedSxact)
3688  {
3689  SERIALIZABLEXACT *nextSxact;
3690 
3691  nextSxact = (SERIALIZABLEXACT *)
3693  &(finishedSxact->finishedLink),
3694  offsetof(SERIALIZABLEXACT, finishedLink));
3698  {
3699  /*
3700  * This transaction committed before any in-progress transaction
3701  * took its snapshot. It's no longer interesting.
3702  */
3703  LWLockRelease(SerializableXactHashLock);
3704  SHMQueueDelete(&(finishedSxact->finishedLink));
3705  ReleaseOneSerializableXact(finishedSxact, false, false);
3706  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3707  }
3708  else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3709  && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3710  {
3711  /*
3712  * Any active transactions that took their snapshot before this
3713  * transaction committed are read-only, so we can clear part of
3714  * its state.
3715  */
3716  LWLockRelease(SerializableXactHashLock);
3717 
3718  if (SxactIsReadOnly(finishedSxact))
3719  {
3720  /* A read-only transaction can be removed entirely */
3721  SHMQueueDelete(&(finishedSxact->finishedLink));
3722  ReleaseOneSerializableXact(finishedSxact, false, false);
3723  }
3724  else
3725  {
3726  /*
3727  * A read-write transaction can only be partially cleared. We
3728  * need to keep the SERIALIZABLEXACT but can release the
3729  * SIREAD locks and conflicts in.
3730  */
3731  ReleaseOneSerializableXact(finishedSxact, true, false);
3732  }
3733 
3735  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3736  }
3737  else
3738  {
3739  /* Still interesting. */
3740  break;
3741  }
3742  finishedSxact = nextSxact;
3743  }
3744  LWLockRelease(SerializableXactHashLock);
3745 
3746  /*
3747  * Loop through predicate locks on dummy transaction for summarized data.
3748  */
3749  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
3750  predlock = (PREDICATELOCK *)
3753  offsetof(PREDICATELOCK, xactLink));
3754  while (predlock)
3755  {
3756  PREDICATELOCK *nextpredlock;
3757  bool canDoPartialCleanup;
3758 
3759  nextpredlock = (PREDICATELOCK *)
3761  &predlock->xactLink,
3762  offsetof(PREDICATELOCK, xactLink));
3763 
3764  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3765  Assert(predlock->commitSeqNo != 0);
3767  canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
3768  LWLockRelease(SerializableXactHashLock);
3769 
3770  /*
3771  * If this lock originally belonged to an old enough transaction, we
3772  * can release it.
3773  */
3774  if (canDoPartialCleanup)
3775  {
3776  PREDICATELOCKTAG tag;
3777  PREDICATELOCKTARGET *target;
3778  PREDICATELOCKTARGETTAG targettag;
3779  uint32 targettaghash;
3780  LWLock *partitionLock;
3781 
3782  tag = predlock->tag;
3783  target = tag.myTarget;
3784  targettag = target->tag;
3785  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3786  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3787 
3788  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3789 
3790  SHMQueueDelete(&(predlock->targetLink));
3791  SHMQueueDelete(&(predlock->xactLink));
3792 
3795  targettaghash),
3796  HASH_REMOVE, NULL);
3797  RemoveTargetIfNoLongerUsed(target, targettaghash);
3798 
3799  LWLockRelease(partitionLock);
3800  }
3801 
3802  predlock = nextpredlock;
3803  }
3804 
3805  LWLockRelease(SerializablePredicateListLock);
3806  LWLockRelease(SerializableFinishedListLock);
3807 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:932
#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:2094
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
#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:429
#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:3829
#define Assert(condition)
Definition: c.h:800
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
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:723
PREDICATELOCKTARGET * myTarget

◆ CoarserLockCovers()

static bool CoarserLockCovers ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2022 of file predicate.c.

References GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

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

◆ CreateLocalPredicateLockHash()

static void CreateLocalPredicateLockHash ( void  )
static

Definition at line 1850 of file predicate.c.

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

Referenced by AttachSerializableXact(), and GetSerializableTransactionSnapshotInt().

1851 {
1852  HASHCTL hash_ctl;
1853 
1854  /* Initialize the backend-local hash table of parent locks */
1855  Assert(LocalPredicateLockHash == NULL);
1856  MemSet(&hash_ctl, 0, sizeof(hash_ctl));
1857  hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1858  hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1859  LocalPredicateLockHash = hash_create("Local predicate lock",
1861  &hash_ctl,
1862  HASH_ELEM | HASH_BLOBS);
1863 }
#define HASH_ELEM
Definition: hsearch.h:85
Size entrysize
Definition: hsearch.h:72
#define MemSet(start, val, len)
Definition: c.h:1004
int max_predicate_locks_per_xact
Definition: predicate.c:366
struct LOCALPREDICATELOCK LOCALPREDICATELOCK
#define HASH_BLOBS
Definition: hsearch.h:86
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:326
Size keysize
Definition: hsearch.h:71
#define Assert(condition)
Definition: c.h:800
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 2374 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().

2377 {
2378  PREDICATELOCKTARGET *target;
2379  PREDICATELOCKTAG locktag;
2380  PREDICATELOCK *lock;
2381  LWLock *partitionLock;
2382  bool found;
2383 
2384  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2385 
2386  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2387  if (IsInParallelMode())
2389  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2390 
2391  /* Make sure that the target is represented. */
2392  target = (PREDICATELOCKTARGET *)
2394  targettag, targettaghash,
2395  HASH_ENTER_NULL, &found);
2396  if (!target)
2397  ereport(ERROR,
2398  (errcode(ERRCODE_OUT_OF_MEMORY),
2399  errmsg("out of shared memory"),
2400  errhint("You might need to increase max_pred_locks_per_transaction.")));
2401  if (!found)
2402  SHMQueueInit(&(target->predicateLocks));
2403 
2404  /* We've got the sxact and target, make sure they're joined. */
2405  locktag.myTarget = target;
2406  locktag.myXact = sxact;
2407  lock = (PREDICATELOCK *)
2409  PredicateLockHashCodeFromTargetHashCode(&locktag, targettaghash),
2410  HASH_ENTER_NULL, &found);
2411  if (!lock)
2412  ereport(ERROR,
2413  (errcode(ERRCODE_OUT_OF_MEMORY),
2414  errmsg("out of shared memory"),
2415  errhint("You might need to increase max_pred_locks_per_transaction.")));
2416 
2417  if (!found)
2418  {
2419  SHMQueueInsertBefore(&(target->predicateLocks), &(lock->targetLink));
2421  &(lock->xactLink));
2423  }
2424 
2425  LWLockRelease(partitionLock);
2426  if (IsInParallelMode())
2428  LWLockRelease(SerializablePredicateListLock);
2429 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:932
Definition: lwlock.h:31
static HTAB * PredicateLockTargetHash
Definition: predicate.c:392
int errhint(const char *fmt,...)
Definition: elog.c:1149
int errcode(int sqlerrcode)
Definition: elog.c:691
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:1811
bool IsInParallelMode(void)
Definition: xact.c:1012
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:311
#define ERROR
Definition: elog.h:43
static HTAB * PredicateLockHash
Definition: predicate.c:393
#define InvalidSerCommitSeqNo
#define ereport(elevel,...)
Definition: elog.h:155
SerCommitSeqNo commitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
int errmsg(const char *fmt,...)
Definition: elog.c:902
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:723

◆ DecrementParentLocks()

static void DecrementParentLocks ( const PREDICATELOCKTARGETTAG targettag)
static

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

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

◆ DeleteChildTargetLocks()

static void DeleteChildTargetLocks ( const PREDICATELOCKTARGETTAG newtargettag)
static

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

2126 {
2127  SERIALIZABLEXACT *sxact;
2128  PREDICATELOCK *predlock;
2129 
2130  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2131  sxact = MySerializableXact;
2132  if (IsInParallelMode())
2134  predlock = (PREDICATELOCK *)
2135  SHMQueueNext(&(sxact->predicateLocks),
2136  &(sxact->predicateLocks),
2137  offsetof(PREDICATELOCK, xactLink));
2138  while (predlock)
2139  {
2140  SHM_QUEUE *predlocksxactlink;
2141  PREDICATELOCK *nextpredlock;
2142  PREDICATELOCKTAG oldlocktag;
2143  PREDICATELOCKTARGET *oldtarget;
2144  PREDICATELOCKTARGETTAG oldtargettag;
2145 
2146  predlocksxactlink = &(predlock->xactLink);
2147  nextpredlock = (PREDICATELOCK *)
2148  SHMQueueNext(&(sxact->predicateLocks),
2149  predlocksxactlink,
2150  offsetof(PREDICATELOCK, xactLink));
2151 
2152  oldlocktag = predlock->tag;
2153  Assert(oldlocktag.myXact == sxact);
2154  oldtarget = oldlocktag.myTarget;
2155  oldtargettag = oldtarget->tag;
2156 
2157  if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
2158  {
2159  uint32 oldtargettaghash;
2160  LWLock *partitionLock;
2162 
2163  oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2164  partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2165 
2166  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2167 
2168  SHMQueueDelete(predlocksxactlink);
2169  SHMQueueDelete(&(predlock->targetLink));
2170  rmpredlock = hash_search_with_hash_value
2172  &oldlocktag,
2174  oldtargettaghash),
2175  HASH_REMOVE, NULL);
2176  Assert(rmpredlock == predlock);
2177 
2178  RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2179 
2180  LWLockRelease(partitionLock);
2181 
2182  DecrementParentLocks(&oldtargettag);
2183  }
2184 
2185  predlock = nextpredlock;
2186  }
2187  if (IsInParallelMode())
2189  LWLockRelease(SerializablePredicateListLock);
2190 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:932
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
Definition: lwlock.h:31
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2094
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
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:429
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2312
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:800
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
#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:723
PREDICATELOCKTARGET * myTarget
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:143

◆ DeleteLockTarget()

static void DeleteLockTarget ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

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

2592 {
2593  PREDICATELOCK *predlock;
2594  SHM_QUEUE *predlocktargetlink;
2595  PREDICATELOCK *nextpredlock;
2596  bool found;
2597 
2598  Assert(LWLockHeldByMeInMode(SerializablePredicateListLock,
2599  LW_EXCLUSIVE));
2601 
2602  predlock = (PREDICATELOCK *)
2603  SHMQueueNext(&(target->predicateLocks),
2604  &(target->predicateLocks),
2605  offsetof(PREDICATELOCK, targetLink));
2606  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2607  while (predlock)
2608  {
2609  predlocktargetlink = &(predlock->targetLink);
2610  nextpredlock = (PREDICATELOCK *)
2611  SHMQueueNext(&(target->predicateLocks),
2612  predlocktargetlink,
2613  offsetof(PREDICATELOCK, targetLink));
2614 
2615  SHMQueueDelete(&(predlock->xactLink));
2616  SHMQueueDelete(&(predlock->targetLink));
2617 
2620  &predlock->tag,
2622  targettaghash),
2623  HASH_REMOVE, &found);
2624  Assert(found);
2625 
2626  predlock = nextpredlock;
2627  }
2628  LWLockRelease(SerializableXactHashLock);
2629 
2630  /* Remove the target itself, if possible. */
2631  RemoveTargetIfNoLongerUsed(target, targettaghash);
2632 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:932
bool LWLockHeldByMeInMode(LWLock *l, LWLockMode mode)
Definition: lwlock.c:1945
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1927
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2094
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
#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:800
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
#define offsetof(type, field)
Definition: c.h:723

◆ DropAllPredicateLocksFromTable()

static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
)
static

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

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

◆ FlagRWConflict()

static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

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

4551 {
4552  Assert(reader != writer);
4553 
4554  /* First, see if this conflict causes failure. */
4556 
4557  /* Actually do the conflict flagging. */
4558  if (reader == OldCommittedSxact)
4560  else if (writer == OldCommittedSxact)
4562  else
4563  SetRWConflict(reader, writer);
4564 }
#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:4585
#define Assert(condition)
Definition: c.h:800
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:800
#define SXACT_FLAG_RO_UNSAFE
#define offsetof(type, field)
Definition: c.h:723
SERIALIZABLEXACT * sxactOut

◆ GetParentPredicateLockTag()

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

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

1985 {
1986  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
1987  {
1988  case PREDLOCKTAG_RELATION:
1989  /* relation locks have no parent lock */
1990  return false;
1991 
1992  case PREDLOCKTAG_PAGE:
1993  /* parent lock is relation lock */
1997 
1998  return true;
1999 
2000  case PREDLOCKTAG_TUPLE:
2001  /* parent lock is page lock */
2006  return true;
2007  }
2008 
2009  /* not reachable */
2010  Assert(false);
2011  return false;
2012 }
#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:800

◆ GetPredicateLockStatusData()

PredicateLockData* GetPredicateLockStatusData ( void  )

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

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

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

Referenced by GetSerializableTransactionSnapshot().

1487 {
1488  Snapshot snapshot;
1489 
1491 
1492  while (true)
1493  {
1494  /*
1495  * GetSerializableTransactionSnapshotInt is going to call
1496  * GetSnapshotData, so we need to provide it the static snapshot area
1497  * our caller passed to us. The pointer returned is actually the same
1498  * one passed to it, but we avoid assuming that here.
1499  */
1500  snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
1501  NULL, InvalidPid);
1502 
1504  return snapshot; /* no concurrent r/w xacts; it's safe */
1505 
1506  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1507 
1508  /*
1509  * Wait for concurrent transactions to finish. Stop early if one of
1510  * them marked us as conflicted.
1511  */
1515  {
1516  LWLockRelease(SerializableXactHashLock);
1518  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1519  }
1521 
1523  {
1524  LWLockRelease(SerializableXactHashLock);
1525  break; /* success */
1526  }
1527 
1528  LWLockRelease(SerializableXactHashLock);
1529 
1530  /* else, need to retry... */
1531  ereport(DEBUG2,
1532  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1533  errmsg("deferrable snapshot was unsafe; trying a new one")));
1534  ReleasePredicateLocks(false, false);
1535  }
1536 
1537  /*
1538  * Now we have a safe snapshot, so we don't need to do any further checks.
1539  */
1541  ReleasePredicateLocks(false, true);
1542 
1543  return snapshot;
1544 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
bool XactDeferrable
Definition: xact.c:81
int errcode(int sqlerrcode)
Definition: elog.c:691
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3261
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1690
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:1809
bool SHMQueueEmpty(const SHM_QUEUE *queue)
Definition: shmqueue.c:180
#define ereport(elevel,...)
Definition: elog.h:155
bool XactReadOnly
Definition: xact.c:78
#define Assert(condition)
Definition: c.h:800
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
int errmsg(const char *fmt,...)
Definition: elog.c:902
#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 1556 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().

1557 {
1558  int num_written = 0;
1559  SERIALIZABLEXACT *sxact;
1560 
1561  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1562 
1563  /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
1564  for (sxact = FirstPredXact(); sxact != NULL; sxact = NextPredXact(sxact))
1565  {
1566  if (sxact->pid == blocked_pid)
1567  break;
1568  }
1569 
1570  /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
1571  if (sxact != NULL && SxactIsDeferrableWaiting(sxact))
1572  {
1573  RWConflict possibleUnsafeConflict;
1574 
1575  /* Traverse the list of possible unsafe conflicts collecting PIDs. */
1576  possibleUnsafeConflict = (RWConflict)
1578  &sxact->possibleUnsafeConflicts,
1579  offsetof(RWConflictData, inLink));
1580 
1581  while (possibleUnsafeConflict != NULL && num_written < output_size)
1582  {
1583  output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
1584  possibleUnsafeConflict = (RWConflict)
1586  &possibleUnsafeConflict->inLink,
1587  offsetof(RWConflictData, inLink));
1588  }
1589  }
1590 
1591  LWLockRelease(SerializableXactHashLock);
1592 
1593  return num_written;
1594 }
static void output(uint64 loop_count)
struct RWConflictData * RWConflict
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
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:1207
#define offsetof(type, field)
Definition: c.h:723
SERIALIZABLEXACT * sxactOut

◆ GetSerializableTransactionSnapshot()

Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot)

Definition at line 1608 of file predicate.c.

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

Referenced by GetTransactionSnapshot().

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

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

◆ InitPredicateLocks()

void InitPredicateLocks ( void  )

Definition at line 1078 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, MemSet, 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().

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

◆ MaxPredicateChildLocks()

static int MaxPredicateChildLocks ( const PREDICATELOCKTARGETTAG tag)
static

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

2211 {
2212  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2213  {
2214  case PREDLOCKTAG_RELATION:
2219 
2220  case PREDLOCKTAG_PAGE:
2222 
2223  case PREDLOCKTAG_TUPLE:
2224 
2225  /*
2226  * not reachable: nothing is finer-granularity than a tuple, so we
2227  * should never try to promote to it.
2228  */
2229  Assert(false);
2230  return 0;
2231  }
2232 
2233  /* not reachable */
2234  Assert(false);
2235  return 0;
2236 }
int max_predicate_locks_per_xact
Definition: predicate.c:366
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define Assert(condition)
Definition: c.h:800
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:800
struct PredXactListElementData * PredXactListElement
#define offsetof(type, field)
Definition: c.h:723

◆ OnConflict_CheckForSerializationFailure()

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

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

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

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

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

1920 {
1921  PREDICATELOCKTARGETTAG targettag;
1922  uint32 targettaghash;
1923  LWLock *partitionLock;
1924  PREDICATELOCKTARGET *target;
1925 
1927  relation->rd_node.dbNode,
1928  relation->rd_id,
1929  blkno);
1930 
1931  targettaghash = PredicateLockTargetTagHashCode(&targettag);
1932  partitionLock = PredicateLockHashPartitionLock(targettaghash);
1933  LWLockAcquire(partitionLock, LW_SHARED);
1934  target = (PREDICATELOCKTARGET *)
1936  &targettag, targettaghash,
1937  HASH_FIND, NULL);
1938  LWLockRelease(partitionLock);
1939 
1940  return (target != NULL);
1941 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:932
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:1811
unsigned int uint32
Definition: c.h:429
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:1207

◆ PostPrepare_PredicateLocks()

void PostPrepare_PredicateLocks ( TransactionId  xid)

Definition at line 4930 of file predicate.c.

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

Referenced by PrepareTransaction().

4931 {
4933  return;
4934 
4936 
4937  MySerializableXact->pid = 0;
4938 
4940  LocalPredicateLockHash = NULL;
4941 
4943  MyXactDidWrite = false;
4944 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:827
#define SxactIsPrepared(sxact)
Definition: predicate.c:273
#define InvalidSerializableXact
#define Assert(condition)
Definition: c.h:800
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409
static bool MyXactDidWrite
Definition: predicate.c:417

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

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

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

◆ predicatelock_hash()

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

Definition at line 1345 of file predicate.c.

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

Referenced by InitPredicateLocks().

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

◆ predicatelock_twophase_recover()

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

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

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

◆ PredicateLockAcquire()

static void PredicateLockAcquire ( const PREDICATELOCKTARGETTAG targettag)
static

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

2440 {
2441  uint32 targettaghash;
2442  bool found;
2443  LOCALPREDICATELOCK *locallock;
2444 
2445  /* Do we have the lock already, or a covering lock? */
2446  if (PredicateLockExists(targettag))
2447  return;
2448 
2449  if (CoarserLockCovers(targettag))
2450  return;
2451 
2452  /* the same hash and LW lock apply to the lock target and the local lock. */
2453  targettaghash = PredicateLockTargetTagHashCode(targettag);
2454 
2455  /* Acquire lock in local table */
2456  locallock = (LOCALPREDICATELOCK *)
2458  targettag, targettaghash,
2459  HASH_ENTER, &found);
2460  locallock->held = true;
2461  if (!found)
2462  locallock->childLocks = 0;
2463 
2464  /* Actually create the lock */
2465  CreatePredicateLock(targettag, targettaghash, MySerializableXact);
2466 
2467  /*
2468  * Lock has been acquired. Check whether it should be promoted to a
2469  * coarser granularity, or whether there are finer-granularity locks to
2470  * clean up.
2471  */
2472  if (CheckAndPromotePredicateLockRequest(targettag))
2473  {
2474  /*
2475  * Lock request was promoted to a coarser-granularity lock, and that
2476  * lock was acquired. It will delete this lock and any of its
2477  * children, so we're done.
2478  */
2479  }
2480  else
2481  {
2482  /* Clean up any finer-granularity locks */
2484  DeleteChildTargetLocks(targettag);
2485  }
2486 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:932
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2374
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:1956
static void DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
Definition: predicate.c:2125
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
unsigned int uint32
Definition: c.h:429
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
static bool CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag)
Definition: predicate.c:2247
static HTAB * LocalPredicateLockHash
Definition: predicate.c:409
static bool CoarserLockCovers(const PREDICATELOCKTARGETTAG *newtargettag)
Definition: predicate.c:2022

◆ PredicateLockExists()

static bool PredicateLockExists ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 1956 of file predicate.c.

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

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

1957 {
1958  LOCALPREDICATELOCK *lock;
1959 
1960  /* check local hash table */
1962  targettag,
1963  HASH_FIND, NULL);
1964 
1965  if (!lock)
1966  return false;
1967 
1968  /*
1969  * Found entry in the table, but still need to check whether it's actually
1970  * held -- it could just be a parent of some held lock.
1971  */
1972  return lock->held;
1973 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
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 2521 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().

2522 {
2524 
2525  if (!SerializationNeededForRead(relation, snapshot))
2526  return;
2527 
2529  relation->rd_node.dbNode,
2530  relation->rd_id,
2531  blkno);
2532  PredicateLockAcquire(&tag);
2533 }
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2439
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 3181 of file predicate.c.

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

3183 {
3184  /*
3185  * Page combines differ from page splits in that we ought to be able to
3186  * remove the locks on the old page after transferring them to the new
3187  * page, instead of duplicating them. However, because we can't edit other
3188  * backends' local lock tables, removing the old lock would leave them
3189  * with an entry in their LocalPredicateLockHash for a lock they're not
3190  * holding, which isn't acceptable. So we wind up having to do the same
3191  * work as a page split, acquiring a lock on the new page and keeping the
3192  * old page locked too. That can lead to some false positives, but should
3193  * be rare in practice.
3194  */
3195  PredicateLockPageSplit(relation, oldblkno, newblkno);
3196 }
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3096

◆ PredicateLockPageSplit()

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

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

3098 {
3099  PREDICATELOCKTARGETTAG oldtargettag;
3100  PREDICATELOCKTARGETTAG newtargettag;
3101  bool success;
3102 
3103  /*
3104  * Bail out quickly if there are no serializable transactions running.
3105  *
3106  * It's safe to do this check without taking any additional locks. Even if
3107  * a serializable transaction starts concurrently, we know it can't take
3108  * any SIREAD locks on the page being split because the caller is holding
3109  * the associated buffer page lock. Memory reordering isn't an issue; the
3110  * memory barrier in the LWLock acquisition guarantees that this read
3111  * occurs while the buffer page lock is held.
3112  */
3114  return;
3115 
3116  if (!PredicateLockingNeededForRelation(relation))
3117  return;
3118 
3119  Assert(oldblkno != newblkno);
3120  Assert(BlockNumberIsValid(oldblkno));
3121  Assert(BlockNumberIsValid(newblkno));
3122 
3123  SET_PREDICATELOCKTARGETTAG_PAGE(oldtargettag,
3124  relation->rd_node.dbNode,
3125  relation->rd_id,
3126  oldblkno);
3127  SET_PREDICATELOCKTARGETTAG_PAGE(newtargettag,
3128  relation->rd_node.dbNode,
3129  relation->rd_id,
3130  newblkno);
3131 
3132  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
3133 
3134  /*
3135  * Try copying the locks over to the new page's tag, creating it if
3136  * necessary.
3137  */
3138  success = TransferPredicateLocksToNewTarget(oldtargettag,
3139  newtargettag,
3140  false);
3141 
3142  if (!success)
3143  {
3144  /*
3145  * No more predicate lock entries are available. Failure isn't an
3146  * option here, so promote the page lock to a relation lock.
3147  */
3148 
3149  /* Get the parent relation lock's lock tag */
3150  success = GetParentPredicateLockTag(&oldtargettag,
3151  &newtargettag);
3152  Assert(success);
3153 
3154  /*
3155  * Move the locks to the parent. This shouldn't fail.
3156  *
3157  * Note that here we are removing locks held by other backends,
3158  * leading to a possible inconsistency in their local lock hash table.
3159  * This is OK because we're replacing it with a lock that covers the
3160  * old one.
3161  */
3162  success = TransferPredicateLocksToNewTarget(oldtargettag,
3163  newtargettag,
3164  true);
3165  Assert(success);
3166  }
3167 
3168  LWLockRelease(SerializablePredicateListLock);
3169 }
static bool PredicateLockingNeededForRelation(Relation relation)
Definition: predicate.c:495
static bool TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag, PREDICATELOCKTARGETTAG newtargettag, bool removeOld)
Definition: predicate.c:2662
static PredXactList PredXact
Definition: predicate.c:379
TransactionId SxactGlobalXmin
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
Oid rd_id
Definition: rel.h:112