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

Go to the source code of this file.

Data Structures

struct  SerialControlData
 

Macros

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

Typedefs

typedef struct SerialControlData SerialControlData
 
typedef struct SerialControlDataSerialControl
 

Functions

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

Variables

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

Macro Definition Documentation

◆ NPREDICATELOCKTARGETENTS

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

Definition at line 259 of file predicate.c.

◆ PredicateLockHashCodeFromTargetHashCode

#define PredicateLockHashCodeFromTargetHashCode (   predicatelocktag,
  targethash 
)
Value:
((targethash) ^ ((uint32) PointerGetDatum((predicatelocktag)->myXact)) \
unsigned int uint32
Definition: c.h:441
#define LOG2_NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:90
#define PointerGetDatum(X)
Definition: postgres.h:600

Definition at line 311 of file predicate.c.

◆ PredicateLockHashPartition

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

Definition at line 251 of file predicate.c.

◆ PredicateLockHashPartitionLock

#define PredicateLockHashPartitionLock (   hashcode)
Value:
PredicateLockHashPartition(hashcode)].lock)
LWLockPadded * MainLWLockArray
Definition: lwlock.c:205
#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET
Definition: lwlock.h:97
LWLock lock
Definition: lwlock.h:57

Definition at line 253 of file predicate.c.

◆ PredicateLockHashPartitionLockByIndex

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

Definition at line 256 of file predicate.c.

◆ PredicateLockTargetTagHashCode

#define PredicateLockTargetTagHashCode (   predicatelocktargettag)     get_hash_value(PredicateLockTargetHash, predicatelocktargettag)

Definition at line 298 of file predicate.c.

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

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

◆ SerialPage

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

Definition at line 338 of file predicate.c.

◆ SerialSlruCtl

#define SerialSlruCtl   (&SerialSlruCtlData)

Definition at line 321 of file predicate.c.

◆ SerialValue

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

Definition at line 334 of file predicate.c.

◆ SxactHasConflictOut

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

Definition at line 284 of file predicate.c.

◆ SxactHasSummaryConflictIn

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

Definition at line 277 of file predicate.c.

◆ SxactHasSummaryConflictOut

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

Definition at line 278 of file predicate.c.

◆ SxactIsCommitted

#define SxactIsCommitted (   sxact)    (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)

Definition at line 272 of file predicate.c.

◆ SxactIsDeferrableWaiting

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

Definition at line 285 of file predicate.c.

◆ SxactIsDoomed

#define SxactIsDoomed (   sxact)    (((sxact)->flags & SXACT_FLAG_DOOMED) != 0)

Definition at line 275 of file predicate.c.

◆ SxactIsOnFinishedList

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

Definition at line 262 of file predicate.c.

◆ SxactIsPartiallyReleased

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

Definition at line 288 of file predicate.c.

◆ SxactIsPrepared

#define SxactIsPrepared (   sxact)    (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)

Definition at line 273 of file predicate.c.

◆ SxactIsReadOnly

#define SxactIsReadOnly (   sxact)    (((sxact)->flags & SXACT_FLAG_READ_ONLY) != 0)

Definition at line 276 of file predicate.c.

◆ SxactIsRolledBack

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

Definition at line 274 of file predicate.c.

◆ SxactIsROSafe

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

Definition at line 286 of file predicate.c.

◆ SxactIsROUnsafe

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

Definition at line 287 of file predicate.c.

◆ 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 InvalidBlockNumber
Definition: block.h:33
#define InvalidOffsetNumber
Definition: off.h:26
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
#define GET_PREDICATELOCKTARGETTAG_PAGE(locktag)
#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag)

Definition at line 228 of file predicate.c.

Typedef Documentation

◆ SerialControl

Definition at line 347 of file predicate.c.

◆ SerialControlData

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4927 of file predicate.c.

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

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

◆ AttachSerializableXact()

void AttachSerializableXact ( SerializableXactHandle  handle)

Definition at line 5199 of file predicate.c.

5200 {
5201 
5203 
5204  MySerializableXact = (SERIALIZABLEXACT *) handle;
5207 }
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1924

References Assert(), CreateLocalPredicateLockHash(), InvalidSerializableXact, and MySerializableXact.

Referenced by ParallelWorkerMain().

◆ CheckAndPromotePredicateLockRequest()

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2320 of file predicate.c.

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

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

Referenced by PredicateLockAcquire().

◆ CheckForSerializableConflictIn()

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

Definition at line 4448 of file predicate.c.

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

References CheckTargetForConflictsIn(), RelFileNode::dbNode, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, InvalidBlockNumber, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, MySerializableXact, 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().

◆ CheckForSerializableConflictOut()

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

Definition at line 4123 of file predicate.c.

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

References Assert(), SERIALIZABLEXACT::earliestOutConflictCommit, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, FlagRWConflict(), SERIALIZABLEXACT::flags, GetTopTransactionIdIfAny(), HASH_FIND, hash_search(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXID::myXact, RWConflictExists(), SERIALIZABLEXACT::SeqNo, SerialGetMinConflictCommitSeqNo(), SerializableXidHash, 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().

◆ CheckForSerializableConflictOutNeeded()

bool CheckForSerializableConflictOutNeeded ( Relation  relation,
Snapshot  snapshot 
)

Definition at line 4091 of file predicate.c.

4092 {
4093  if (!SerializationNeededForRead(relation, snapshot))
4094  return false;
4095 
4096  /* Check if someone else has already decided that we need to die */
4098  {
4099  ereport(ERROR,
4101  errmsg("could not serialize access due to read/write dependencies among transactions"),
4102  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4103  errhint("The transaction might succeed if retried.")));
4104  }
4105 
4106  return true;
4107 }

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

Referenced by HeapCheckForSerializableConflictOut().

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 1069 of file predicate.c.

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

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

Referenced by CheckPointGuts().

◆ CheckTableForSerializableConflictIn()

void CheckTableForSerializableConflictIn ( Relation  relation)

Definition at line 4531 of file predicate.c.

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

References Assert(), RelFileNode::dbNode, FlagRWConflict(), GET_PREDICATELOCKTARGETTAG_DB, GET_PREDICATELOCKTARGETTAG_RELATION, hash_seq_init(), hash_seq_search(), i, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myXact, MyXactDidWrite, NUM_PREDICATELOCK_PARTITIONS, offsetof, PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredXact, 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().

◆ CheckTargetForConflictsIn()

static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag)
static

Definition at line 4266 of file predicate.c.

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

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

Referenced by CheckForSerializableConflictIn().

◆ ClearOldPredicateLocks()

static void ClearOldPredicateLocks ( void  )
static

Definition at line 3745 of file predicate.c.

3746 {
3747  SERIALIZABLEXACT *finishedSxact;
3748  PREDICATELOCK *predlock;
3749 
3750  /*
3751  * Loop through finished transactions. They are in commit order, so we can
3752  * stop as soon as we find one that's still interesting.
3753  */
3754  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3755  finishedSxact = (SERIALIZABLEXACT *)
3758  offsetof(SERIALIZABLEXACT, finishedLink));
3759  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3760  while (finishedSxact)
3761  {
3762  SERIALIZABLEXACT *nextSxact;
3763 
3764  nextSxact = (SERIALIZABLEXACT *)
3766  &(finishedSxact->finishedLink),
3767  offsetof(SERIALIZABLEXACT, finishedLink));
3771  {
3772  /*
3773  * This transaction committed before any in-progress transaction
3774  * took its snapshot. It's no longer interesting.
3775  */
3776  LWLockRelease(SerializableXactHashLock);
3777  SHMQueueDelete(&(finishedSxact->finishedLink));
3778  ReleaseOneSerializableXact(finishedSxact, false, false);
3779  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3780  }
3781  else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3782  && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3783  {
3784  /*
3785  * Any active transactions that took their snapshot before this
3786  * transaction committed are read-only, so we can clear part of
3787  * its state.
3788  */
3789  LWLockRelease(SerializableXactHashLock);
3790 
3791  if (SxactIsReadOnly(finishedSxact))
3792  {
3793  /* A read-only transaction can be removed entirely */
3794  SHMQueueDelete(&(finishedSxact->finishedLink));
3795  ReleaseOneSerializableXact(finishedSxact, false, false);
3796  }
3797  else
3798  {
3799  /*
3800  * A read-write transaction can only be partially cleared. We
3801  * need to keep the SERIALIZABLEXACT but can release the
3802  * SIREAD locks and conflicts in.
3803  */
3804  ReleaseOneSerializableXact(finishedSxact, true, false);
3805  }
3806 
3808  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3809  }
3810  else
3811  {
3812  /* Still interesting. */
3813  break;
3814  }
3815  finishedSxact = nextSxact;
3816  }
3817  LWLockRelease(SerializableXactHashLock);
3818 
3819  /*
3820  * Loop through predicate locks on dummy transaction for summarized data.
3821  */
3822  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
3823  predlock = (PREDICATELOCK *)
3826  offsetof(PREDICATELOCK, xactLink));
3827  while (predlock)
3828  {
3829  PREDICATELOCK *nextpredlock;
3830  bool canDoPartialCleanup;
3831 
3832  nextpredlock = (PREDICATELOCK *)
3834  &predlock->xactLink,
3835  offsetof(PREDICATELOCK, xactLink));
3836 
3837  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3838  Assert(predlock->commitSeqNo != 0);
3840  canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
3841  LWLockRelease(SerializableXactHashLock);
3842 
3843  /*
3844  * If this lock originally belonged to an old enough transaction, we
3845  * can release it.
3846  */
3847  if (canDoPartialCleanup)
3848  {
3849  PREDICATELOCKTAG tag;
3850  PREDICATELOCKTARGET *target;
3851  PREDICATELOCKTARGETTAG targettag;
3852  uint32 targettaghash;
3853  LWLock *partitionLock;
3854 
3855  tag = predlock->tag;
3856  target = tag.myTarget;
3857  targettag = target->tag;
3858  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3859  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3860 
3861  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3862 
3863  SHMQueueDelete(&(predlock->targetLink));
3864  SHMQueueDelete(&(predlock->xactLink));
3865 
3868  targettaghash),
3869  HASH_REMOVE, NULL);
3870  RemoveTargetIfNoLongerUsed(target, targettaghash);
3871 
3872  LWLockRelease(partitionLock);
3873  }
3874 
3875  predlock = nextpredlock;
3876  }
3877 
3878  LWLockRelease(SerializablePredicateListLock);
3879  LWLockRelease(SerializableFinishedListLock);
3880 }
static SHM_QUEUE * FinishedSerializableTransactions
Definition: predicate.c:394
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:357
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize)
Definition: predicate.c:3902
SerCommitSeqNo commitSeqNo
SerCommitSeqNo CanPartialClearThrough
SerCommitSeqNo HavePartialClearedThrough
SerCommitSeqNo commitSeqNo
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319

References Assert(), PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, PREDICATELOCK::commitSeqNo, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, HASH_REMOVE, hash_search_with_hash_value(), PredXactListData::HavePartialClearedThrough, InvalidSerCommitSeqNo, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, offsetof, OldCommittedSxact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, PredXact, ReleaseOneSerializableXact(), RemoveTargetIfNoLongerUsed(), SHMQueueDelete(), SHMQueueNext(), PredXactListData::SxactGlobalXmin, SxactIsReadOnly, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdIsValid, TransactionIdPrecedesOrEquals(), and PREDICATELOCK::xactLink.

Referenced by ReleasePredicateLocks().

◆ CoarserLockCovers()

static bool CoarserLockCovers ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2095 of file predicate.c.

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

References GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

◆ CreateLocalPredicateLockHash()

static void CreateLocalPredicateLockHash ( void  )
static

Definition at line 1924 of file predicate.c.

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

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

Referenced by AttachSerializableXact(), and GetSerializableTransactionSnapshotInt().

◆ CreatePredicateLock()

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

Definition at line 2447 of file predicate.c.

2450 {
2451  PREDICATELOCKTARGET *target;
2452  PREDICATELOCKTAG locktag;
2453  PREDICATELOCK *lock;
2454  LWLock *partitionLock;
2455  bool found;
2456 
2457  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2458 
2459  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2460  if (IsInParallelMode())
2462  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2463 
2464  /* Make sure that the target is represented. */
2465  target = (PREDICATELOCKTARGET *)
2467  targettag, targettaghash,
2468  HASH_ENTER_NULL, &found);
2469  if (!target)
2470  ereport(ERROR,
2471  (errcode(ERRCODE_OUT_OF_MEMORY),
2472  errmsg("out of shared memory"),
2473  errhint("You might need to increase max_pred_locks_per_transaction.")));
2474  if (!found)
2475  SHMQueueInit(&(target->predicateLocks));
2476 
2477  /* We've got the sxact and target, make sure they're joined. */
2478  locktag.myTarget = target;
2479  locktag.myXact = sxact;
2480  lock = (PREDICATELOCK *)
2482  PredicateLockHashCodeFromTargetHashCode(&locktag, targettaghash),
2483  HASH_ENTER_NULL, &found);
2484  if (!lock)
2485  ereport(ERROR,
2486  (errcode(ERRCODE_OUT_OF_MEMORY),
2487  errmsg("out of shared memory"),
2488  errhint("You might need to increase max_pred_locks_per_transaction.")));
2489 
2490  if (!found)
2491  {
2492  SHMQueueInsertBefore(&(target->predicateLocks), &(lock->targetLink));
2494  &(lock->xactLink));
2496  }
2497 
2498  LWLockRelease(partitionLock);
2499  if (IsInParallelMode())
2501  LWLockRelease(SerializablePredicateListLock);
2502 }
@ HASH_ENTER_NULL
Definition: hsearch.h:116
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89

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, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, SHMQueueInit(), SHMQueueInsertBefore(), PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by predicatelock_twophase_recover(), and PredicateLockAcquire().

◆ CreatePredXact()

◆ DecrementParentLocks()

static void DecrementParentLocks ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2385 of file predicate.c.

2386 {
2387  PREDICATELOCKTARGETTAG parenttag,
2388  nexttag;
2389 
2390  parenttag = *targettag;
2391 
2392  while (GetParentPredicateLockTag(&parenttag, &nexttag))
2393  {
2394  uint32 targettaghash;
2395  LOCALPREDICATELOCK *parentlock,
2396  *rmlock PG_USED_FOR_ASSERTS_ONLY;
2397 
2398  parenttag = nexttag;
2399  targettaghash = PredicateLockTargetTagHashCode(&parenttag);
2400  parentlock = (LOCALPREDICATELOCK *)
2402  &parenttag, targettaghash,
2403  HASH_FIND, NULL);
2404 
2405  /*
2406  * There's a small chance the parent lock doesn't exist in the lock
2407  * table. This can happen if we prematurely removed it because an
2408  * index split caused the child refcount to be off.
2409  */
2410  if (parentlock == NULL)
2411  continue;
2412 
2413  parentlock->childLocks--;
2414 
2415  /*
2416  * Under similar circumstances the parent lock's refcount might be
2417  * zero. This only happens if we're holding that lock (otherwise we
2418  * would have removed the entry).
2419  */
2420  if (parentlock->childLocks < 0)
2421  {
2422  Assert(parentlock->held);
2423  parentlock->childLocks = 0;
2424  }
2425 
2426  if ((parentlock->childLocks == 0) && (!parentlock->held))
2427  {
2428  rmlock = (LOCALPREDICATELOCK *)
2430  &parenttag, targettaghash,
2431  HASH_REMOVE, NULL);
2432  Assert(rmlock == parentlock);
2433  }
2434  }
2435 }
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:155

References Assert(), LOCALPREDICATELOCK::childLocks, GetParentPredicateLockTag(), HASH_FIND, HASH_REMOVE, hash_search_with_hash_value(), LOCALPREDICATELOCK::held, LocalPredicateLockHash, PG_USED_FOR_ASSERTS_ONLY, and PredicateLockTargetTagHashCode.

Referenced by CheckTargetForConflictsIn(), and DeleteChildTargetLocks().

◆ DeleteChildTargetLocks()

static void DeleteChildTargetLocks ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2198 of file predicate.c.

2199 {
2200  SERIALIZABLEXACT *sxact;
2201  PREDICATELOCK *predlock;
2202 
2203  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2204  sxact = MySerializableXact;
2205  if (IsInParallelMode())
2207  predlock = (PREDICATELOCK *)
2208  SHMQueueNext(&(sxact->predicateLocks),
2209  &(sxact->predicateLocks),
2210  offsetof(PREDICATELOCK, xactLink));
2211  while (predlock)
2212  {
2213  SHM_QUEUE *predlocksxactlink;
2214  PREDICATELOCK *nextpredlock;
2215  PREDICATELOCKTAG oldlocktag;
2216  PREDICATELOCKTARGET *oldtarget;
2217  PREDICATELOCKTARGETTAG oldtargettag;
2218 
2219  predlocksxactlink = &(predlock->xactLink);
2220  nextpredlock = (PREDICATELOCK *)
2221  SHMQueueNext(&(sxact->predicateLocks),
2222  predlocksxactlink,
2223  offsetof(PREDICATELOCK, xactLink));
2224 
2225  oldlocktag = predlock->tag;
2226  Assert(oldlocktag.myXact == sxact);
2227  oldtarget = oldlocktag.myTarget;
2228  oldtargettag = oldtarget->tag;
2229 
2230  if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
2231  {
2232  uint32 oldtargettaghash;
2233  LWLock *partitionLock;
2235 
2236  oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2237  partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2238 
2239  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2240 
2241  SHMQueueDelete(predlocksxactlink);
2242  SHMQueueDelete(&(predlock->targetLink));
2243  rmpredlock = hash_search_with_hash_value
2245  &oldlocktag,
2247  oldtargettaghash),
2248  HASH_REMOVE, NULL);
2249  Assert(rmpredlock == predlock);
2250 
2251  RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2252 
2253  LWLockRelease(partitionLock);
2254 
2255  DecrementParentLocks(&oldtargettag);
2256  }
2257 
2258  predlock = nextpredlock;
2259  }
2260  if (IsInParallelMode())
2262  LWLockRelease(SerializablePredicateListLock);
2263 }
#define TargetTagIsCoveredBy(covered_target, covering_target)
Definition: predicate.c:228

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, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, RemoveTargetIfNoLongerUsed(), SHMQueueDelete(), SHMQueueNext(), PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TargetTagIsCoveredBy, and PREDICATELOCK::xactLink.

Referenced by PredicateLockAcquire().

◆ DeleteLockTarget()

static void DeleteLockTarget ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

Definition at line 2664 of file predicate.c.

2665 {
2666  PREDICATELOCK *predlock;
2667  SHM_QUEUE *predlocktargetlink;
2668  PREDICATELOCK *nextpredlock;
2669  bool found;
2670 
2671  Assert(LWLockHeldByMeInMode(SerializablePredicateListLock,
2672  LW_EXCLUSIVE));
2674 
2675  predlock = (PREDICATELOCK *)
2676  SHMQueueNext(&(target->predicateLocks),
2677  &(target->predicateLocks),
2678  offsetof(PREDICATELOCK, targetLink));
2679  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2680  while (predlock)
2681  {
2682  predlocktargetlink = &(predlock->targetLink);
2683  nextpredlock = (PREDICATELOCK *)
2684  SHMQueueNext(&(target->predicateLocks),
2685  predlocktargetlink,
2686  offsetof(PREDICATELOCK, targetLink));
2687 
2688  SHMQueueDelete(&(predlock->xactLink));
2689  SHMQueueDelete(&(predlock->targetLink));
2690 
2693  &predlock->tag,
2695  targettaghash),
2696  HASH_REMOVE, &found);
2697  Assert(found);
2698 
2699  predlock = nextpredlock;
2700  }
2701  LWLockRelease(SerializableXactHashLock);
2702 
2703  /* Remove the target itself, if possible. */
2704  RemoveTargetIfNoLongerUsed(target, targettaghash);
2705 }
bool LWLockHeldByMeInMode(LWLock *l, LWLockMode mode)
Definition: lwlock.c:1934
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1916

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

Referenced by TransferPredicateLocksToNewTarget().

◆ DropAllPredicateLocksFromTable()

static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
)
static

Definition at line 2952 of file predicate.c.

2953 {
2954  HASH_SEQ_STATUS seqstat;
2955  PREDICATELOCKTARGET *oldtarget;
2956  PREDICATELOCKTARGET *heaptarget;
2957  Oid dbId;
2958  Oid relId;
2959  Oid heapId;
2960  int i;
2961  bool isIndex;
2962  bool found;
2963  uint32 heaptargettaghash;
2964 
2965  /*
2966  * Bail out quickly if there are no serializable transactions running.
2967  * It's safe to check this without taking locks because the caller is
2968  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
2969  * would matter here can be acquired while that is held.
2970  */
2972  return;
2973 
2974  if (!PredicateLockingNeededForRelation(relation))
2975  return;
2976 
2977  dbId = relation->rd_node.dbNode;
2978  relId = relation->rd_id;
2979  if (relation->rd_index == NULL)
2980  {
2981  isIndex = false;
2982  heapId = relId;
2983  }
2984  else
2985  {
2986  isIndex = true;
2987  heapId = relation->rd_index->indrelid;
2988  }
2989  Assert(heapId != InvalidOid);
2990  Assert(transfer || !isIndex); /* index OID only makes sense with
2991  * transfer */
2992 
2993  /* Retrieve first time needed, then keep. */
2994  heaptargettaghash = 0;
2995  heaptarget = NULL;
2996 
2997  /* Acquire locks on all lock partitions */
2998  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
2999  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
3001  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3002 
3003  /*
3004  * Remove the dummy entry to give us scratch space, so we know we'll be
3005  * able to create the new lock target.
3006  */
3007  if (transfer)
3008  RemoveScratchTarget(true);
3009 
3010  /* Scan through target map */
3012 
3013  while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
3014  {
3015  PREDICATELOCK *oldpredlock;
3016 
3017  /*
3018  * Check whether this is a target which needs attention.
3019  */
3020  if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) != relId)
3021  continue; /* wrong relation id */
3022  if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
3023  continue; /* wrong database id */
3024  if (transfer && !isIndex
3026  continue; /* already the right lock */
3027 
3028  /*
3029  * If we made it here, we have work to do. We make sure the heap
3030  * relation lock exists, then we walk the list of predicate locks for
3031  * the old target we found, moving all locks to the heap relation lock
3032  * -- unless they already hold that.
3033  */
3034 
3035  /*
3036  * First make sure we have the heap relation target. We only need to
3037  * do this once.
3038  */
3039  if (transfer && heaptarget == NULL)
3040  {
3041  PREDICATELOCKTARGETTAG heaptargettag;
3042 
3043  SET_PREDICATELOCKTARGETTAG_RELATION(heaptargettag, dbId, heapId);
3044  heaptargettaghash = PredicateLockTargetTagHashCode(&heaptargettag);
3046  &heaptargettag,
3047  heaptargettaghash,
3048  HASH_ENTER, &found);
3049  if (!found)
3050  SHMQueueInit(&heaptarget->predicateLocks);
3051  }
3052 
3053  /*
3054  * Loop through all the locks on the old target, replacing them with
3055  * locks on the new target.
3056  */
3057  oldpredlock = (PREDICATELOCK *)
3058  SHMQueueNext(&(oldtarget->predicateLocks),
3059  &(oldtarget->predicateLocks),
3060  offsetof(PREDICATELOCK, targetLink));
3061  while (oldpredlock)
3062  {
3063  PREDICATELOCK *nextpredlock;
3064  PREDICATELOCK *newpredlock;
3065  SerCommitSeqNo oldCommitSeqNo;
3066  SERIALIZABLEXACT *oldXact;
3067 
3068  nextpredlock = (PREDICATELOCK *)
3069  SHMQueueNext(&(oldtarget->predicateLocks),
3070  &(oldpredlock->targetLink),
3071  offsetof(PREDICATELOCK, targetLink));
3072 
3073  /*
3074  * Remove the old lock first. This avoids the chance of running
3075  * out of lock structure entries for the hash table.
3076  */
3077  oldCommitSeqNo = oldpredlock->commitSeqNo;
3078  oldXact = oldpredlock->tag.myXact;
3079 
3080  SHMQueueDelete(&(oldpredlock->xactLink));
3081 
3082  /*
3083  * No need for retail delete from oldtarget list, we're removing
3084  * the whole target anyway.
3085  */
3087  &oldpredlock->tag,
3088  HASH_REMOVE, &found);
3089  Assert(found);
3090 
3091  if (transfer)
3092  {
3093  PREDICATELOCKTAG newpredlocktag;
3094 
3095  newpredlocktag.myTarget = heaptarget;
3096  newpredlocktag.myXact = oldXact;
3097  newpredlock = (PREDICATELOCK *)
3099  &newpredlocktag,
3101  heaptargettaghash),
3102  HASH_ENTER,
3103  &found);
3104  if (!found)
3105  {
3106  SHMQueueInsertBefore(&(heaptarget->predicateLocks),
3107  &(newpredlock->targetLink));
3108  SHMQueueInsertBefore(&(newpredlocktag.myXact->predicateLocks),
3109  &(newpredlock->xactLink));
3110  newpredlock->commitSeqNo = oldCommitSeqNo;
3111  }
3112  else
3113  {
3114  if (newpredlock->commitSeqNo < oldCommitSeqNo)
3115  newpredlock->commitSeqNo = oldCommitSeqNo;
3116  }
3117 
3118  Assert(newpredlock->commitSeqNo != 0);
3119  Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
3120  || (newpredlock->tag.myXact == OldCommittedSxact));
3121  }
3122 
3123  oldpredlock = nextpredlock;
3124  }
3125 
3127  &found);
3128  Assert(found);
3129  }
3130 
3131  /* Put the scratch entry back */
3132  if (transfer)
3133  RestoreScratchTarget(true);
3134 
3135  /* Release locks in reverse order */
3136  LWLockRelease(SerializableXactHashLock);
3137  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3139  LWLockRelease(SerializablePredicateListLock);
3140 }
#define InvalidOid
Definition: postgres_ext.h:36
static bool PredicateLockingNeededForRelation(Relation relation)
Definition: predicate.c:495
static void RestoreScratchTarget(bool lockheld)
Definition: predicate.c:2145
static void RemoveScratchTarget(bool lockheld)
Definition: predicate.c:2124
@ PREDLOCKTAG_RELATION
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)

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, OldCommittedSxact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLockByIndex, PredicateLockingNeededForRelation(), SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredicateLockTargetTagHashCode, PREDLOCKTAG_RELATION, PredXact, 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().

◆ FirstPredXact()

static SERIALIZABLEXACT * FirstPredXact ( void  )
static

Definition at line 612 of file predicate.c.

613 {
614  PredXactListElement ptle;
615 
616  ptle = (PredXactListElement)
620  if (!ptle)
621  return NULL;
622 
623  return &ptle->sxact;
624 }

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

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

◆ FlagRWConflict()

static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4623 of file predicate.c.

4624 {
4625  Assert(reader != writer);
4626 
4627  /* First, see if this conflict causes failure. */
4629 
4630  /* Actually do the conflict flagging. */
4631  if (reader == OldCommittedSxact)
4633  else if (writer == OldCommittedSxact)
4635  else
4636  SetRWConflict(reader, writer);
4637 }
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:686
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4658
#define SXACT_FLAG_SUMMARY_CONFLICT_IN

References Assert(), SERIALIZABLEXACT::flags, OldCommittedSxact, OnConflict_CheckForSerializationFailure(), SetRWConflict(), SXACT_FLAG_SUMMARY_CONFLICT_IN, and SXACT_FLAG_SUMMARY_CONFLICT_OUT.

Referenced by CheckForSerializableConflictOut(), CheckTableForSerializableConflictIn(), and CheckTargetForConflictsIn().

◆ FlagSxactUnsafe()

static void FlagSxactUnsafe ( SERIALIZABLEXACT sxact)
static

Definition at line 750 of file predicate.c.

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 SxactIsROSafe(sxact)
Definition: predicate.c:286
static void ReleaseRWConflict(RWConflict conflict)
Definition: predicate.c:742
struct RWConflictData * RWConflict
#define SXACT_FLAG_RO_UNSAFE
SERIALIZABLEXACT * sxactIn
SERIALIZABLEXACT * sxactOut
SHM_QUEUE possibleUnsafeConflicts

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

◆ GetParentPredicateLockTag()

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

Definition at line 2056 of file predicate.c.

2058 {
2059  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2060  {
2061  case PREDLOCKTAG_RELATION:
2062  /* relation locks have no parent lock */
2063  return false;
2064 
2065  case PREDLOCKTAG_PAGE:
2066  /* parent lock is relation lock */
2070 
2071  return true;
2072 
2073  case PREDLOCKTAG_TUPLE:
2074  /* parent lock is page lock */
2079  return true;
2080  }
2081 
2082  /* not reachable */
2083  Assert(false);
2084  return false;
2085 }
@ PREDLOCKTAG_PAGE
@ PREDLOCKTAG_TUPLE

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

◆ GetPredicateLockStatusData()

PredicateLockData* GetPredicateLockStatusData ( void  )

Definition at line 1444 of file predicate.c.

1445 {
1447  int i;
1448  int els,
1449  el;
1450  HASH_SEQ_STATUS seqstat;
1451  PREDICATELOCK *predlock;
1452 
1454 
1455  /*
1456  * To ensure consistency, take simultaneous locks on all partition locks
1457  * in ascending order, then SerializableXactHashLock.
1458  */
1459  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
1461  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1462 
1463  /* Get number of locks and allocate appropriately-sized arrays. */
1465  data->nelements = els;
1466  data->locktags = (PREDICATELOCKTARGETTAG *)
1467  palloc(sizeof(PREDICATELOCKTARGETTAG) * els);
1468  data->xacts = (SERIALIZABLEXACT *)
1469  palloc(sizeof(SERIALIZABLEXACT) * els);
1470 
1471 
1472  /* Scan through PredicateLockHash and copy contents */
1473  hash_seq_init(&seqstat, PredicateLockHash);
1474 
1475  el = 0;
1476 
1477  while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
1478  {
1479  data->locktags[el] = predlock->tag.myTarget->tag;
1480  data->xacts[el] = *predlock->tag.myXact;
1481  el++;
1482  }
1483 
1484  Assert(el == els);
1485 
1486  /* Release locks in reverse order */
1487  LWLockRelease(SerializableXactHashLock);
1488  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1490 
1491  return data;
1492 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1382
void * palloc(Size size)
Definition: mcxt.c:1068
const void * data

References Assert(), data, hash_get_num_entries(), hash_seq_init(), hash_seq_search(), i, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, NUM_PREDICATELOCK_PARTITIONS, palloc(), PredicateLockHash, PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::tag, and PREDICATELOCK::tag.

Referenced by pg_lock_status().

◆ GetSafeSnapshot()

static Snapshot GetSafeSnapshot ( Snapshot  snapshot)
static

Definition at line 1559 of file predicate.c.

1560 {
1561  Snapshot snapshot;
1562 
1564 
1565  while (true)
1566  {
1567  /*
1568  * GetSerializableTransactionSnapshotInt is going to call
1569  * GetSnapshotData, so we need to provide it the static snapshot area
1570  * our caller passed to us. The pointer returned is actually the same
1571  * one passed to it, but we avoid assuming that here.
1572  */
1573  snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
1574  NULL, InvalidPid);
1575 
1577  return snapshot; /* no concurrent r/w xacts; it's safe */
1578 
1579  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1580 
1581  /*
1582  * Wait for concurrent transactions to finish. Stop early if one of
1583  * them marked us as conflicted.
1584  */
1588  {
1589  LWLockRelease(SerializableXactHashLock);
1591  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1592  }
1594 
1596  {
1597  LWLockRelease(SerializableXactHashLock);
1598  break; /* success */
1599  }
1600 
1601  LWLockRelease(SerializableXactHashLock);
1602 
1603  /* else, need to retry... */
1604  ereport(DEBUG2,
1606  errmsg_internal("deferrable snapshot was unsafe; trying a new one")));
1607  ReleasePredicateLocks(false, false);
1608  }
1609 
1610  /*
1611  * Now we have a safe snapshot, so we don't need to do any further checks.
1612  */
1614  ReleasePredicateLocks(false, true);
1615 
1616  return snapshot;
1617 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:991
#define DEBUG2
Definition: elog.h:23
#define InvalidPid
Definition: miscadmin.h:32
#define SxactIsROUnsafe(sxact)
Definition: predicate.c:287
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1763
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3334
#define SXACT_FLAG_DEFERRABLE_WAITING
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1873
@ WAIT_EVENT_SAFE_SNAPSHOT
Definition: wait_event.h:127
bool XactDeferrable
Definition: xact.c:84
bool XactReadOnly
Definition: xact.c:81

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

Referenced by GetSerializableTransactionSnapshot().

◆ GetSafeSnapshotBlockingPids()

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

Definition at line 1629 of file predicate.c.

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

References FirstPredXact(), RWConflictData::inLink, LW_SHARED, LWLockAcquire(), LWLockRelease(), NextPredXact(), offsetof, output(), SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SHMQueueNext(), SxactIsDeferrableWaiting, and RWConflictData::sxactOut.

Referenced by pg_isolation_test_session_is_blocked(), and pg_safe_snapshot_blocking_pids().

◆ GetSerializableTransactionSnapshot()

Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot)

Definition at line 1681 of file predicate.c.

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

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

Referenced by GetTransactionSnapshot().

◆ GetSerializableTransactionSnapshotInt()

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

Definition at line 1763 of file predicate.c.

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

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, MySerializableXact, MyXactDidWrite, NextPredXact(), SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::pgprocno, PGPROC::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::predicateLocks, PredXact, 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().

◆ InitPredicateLocks()

void InitPredicateLocks ( void  )

Definition at line 1153 of file predicate.c.

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

References PredXactListData::activeList, Assert(), PredXactListData::availableList, RWConflictPoolHeaderData::availableList, PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, CreatePredXact(), PredXactListData::element, RWConflictPoolHeaderData::element, HASHCTL::entrysize, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, 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, INVALID_PGPROCNO, InvalidTransactionId, IsUnderPostmaster, HASHCTL::keysize, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, PredXactListElementData::link, LWLockInitialize(), LWTRANCHE_PER_XACT_PREDICATE_LIST, max_prepared_xacts, MaxBackends, mul_size(), NPREDICATELOCKTARGETENTS, HASHCTL::num_partitions, NUM_PREDICATELOCK_PARTITIONS, OldCommittedSxact, PredXactListData::OldCommittedSxact, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::perXactPredicateListLock, SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, predicatelock_hash(), PredicateLockHash, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetHash, PredicateLockTargetTagHashCode, PredXact, PredXactListDataSize, PredXactListElementDataSize, SERIALIZABLEXACT::prepareSeqNo, RWConflictDataSize, RWConflictPool, RWConflictPoolHeaderDataSize, ScratchPartitionLock, ScratchTargetTag, ScratchTargetTagHash, SERIALIZABLEXACT::SeqNo, SerialInit(), SerializableXidHash, 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().

◆ MaxPredicateChildLocks()

static int MaxPredicateChildLocks ( const PREDICATELOCKTARGETTAG tag)
static

Definition at line 2283 of file predicate.c.

2284 {
2285  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2286  {
2287  case PREDLOCKTAG_RELATION:
2292 
2293  case PREDLOCKTAG_PAGE:
2295 
2296  case PREDLOCKTAG_TUPLE:
2297 
2298  /*
2299  * not reachable: nothing is finer-granularity than a tuple, so we
2300  * should never try to promote to it.
2301  */
2302  Assert(false);
2303  return 0;
2304  }
2305 
2306  /* not reachable */
2307  Assert(false);
2308  return 0;
2309 }
int max_predicate_locks_per_page
Definition: predicate.c:368
int max_predicate_locks_per_relation
Definition: predicate.c:367

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

◆ NextPredXact()

static SERIALIZABLEXACT * NextPredXact ( SERIALIZABLEXACT sxact)
static

Definition at line 627 of file predicate.c.

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 }
bool ShmemAddrIsValid(const void *addr)
Definition: shmem.c:283

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

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

◆ OnConflict_CheckForSerializationFailure()

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

Definition at line 4658 of file predicate.c.

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

References Assert(), SERIALIZABLEXACT::commitSeqNo, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LWLockHeldByMe(), LWLockRelease(), MySerializableXact, 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().

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

Definition at line 1992 of file predicate.c.

1993 {
1994  PREDICATELOCKTARGETTAG targettag;
1995  uint32 targettaghash;
1996  LWLock *partitionLock;
1997  PREDICATELOCKTARGET *target;
1998 
2000  relation->rd_node.dbNode,
2001  relation->rd_id,
2002  blkno);
2003 
2004  targettaghash = PredicateLockTargetTagHashCode(&targettag);
2005  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2006  LWLockAcquire(partitionLock, LW_SHARED);
2007  target = (PREDICATELOCKTARGET *)
2009  &targettag, targettaghash,
2010  HASH_FIND, NULL);
2011  LWLockRelease(partitionLock);
2012 
2013  return (target != NULL);
2014 }

References RelFileNode::dbNode, HASH_FIND, hash_search_with_hash_value(), LW_SHARED, LWLockAcquire(), LWLockRelease(), PredicateLockHashPartitionLock, PredicateLockTargetHash, PredicateLockTargetTagHashCode, RelationData::rd_id, RelationData::rd_node, and SET_PREDICATELOCKTARGETTAG_PAGE.

◆ PostPrepare_PredicateLocks()

void PostPrepare_PredicateLocks ( TransactionId  xid)

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4833 of file predicate.c.

4834 {
4835  RWConflict nearConflict;
4836 
4838  return;
4839 
4841 
4842  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4843 
4844  /* Check if someone else has already decided that we need to die */
4846  {
4848  LWLockRelease(SerializableXactHashLock);
4849  ereport(ERROR,
4851  errmsg("could not serialize access due to read/write dependencies among transactions"),
4852  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4853  errhint("The transaction might succeed if retried.")));
4854  }
4855 
4856  nearConflict = (RWConflict)
4859  offsetof(RWConflictData, inLink));
4860  while (nearConflict)
4861  {
4862  if (!SxactIsCommitted(nearConflict->sxactOut)
4863  && !SxactIsDoomed(nearConflict->sxactOut))
4864  {
4865  RWConflict farConflict;
4866 
4867  farConflict = (RWConflict)
4868  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4869  &nearConflict->sxactOut->inConflicts,
4870  offsetof(RWConflictData, inLink));
4871  while (farConflict)
4872  {
4873  if (farConflict->sxactOut == MySerializableXact
4874  || (!SxactIsCommitted(farConflict->sxactOut)
4875  && !SxactIsReadOnly(farConflict->sxactOut)
4876  && !SxactIsDoomed(farConflict->sxactOut)))
4877  {
4878  /*
4879  * Normally, we kill the pivot transaction to make sure we
4880  * make progress if the failing transaction is retried.
4881  * However, we can't kill it if it's already prepared, so
4882  * in that case we commit suicide instead.
4883  */
4884  if (SxactIsPrepared(nearConflict->sxactOut))
4885  {
4886  LWLockRelease(SerializableXactHashLock);
4887  ereport(ERROR,
4889  errmsg("could not serialize access due to read/write dependencies among transactions"),
4890  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4891  errhint("The transaction might succeed if retried.")));
4892  }
4893  nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4894  break;
4895  }
4896  farConflict = (RWConflict)
4897  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4898  &farConflict->inLink,
4899  offsetof(RWConflictData, inLink));
4900  }
4901  }
4902 
4903  nearConflict = (RWConflict)
4905  &nearConflict->inLink,
4906  offsetof(RWConflictData, inLink));
4907  }
4908 
4911 
4912  LWLockRelease(SerializableXactHashLock);
4913 }
#define SxactIsPartiallyReleased(sxact)
Definition: predicate.c:288
#define SXACT_FLAG_PREPARED

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

Referenced by CommitTransaction(), and PrepareTransaction().

◆ predicatelock_hash()

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

Definition at line 1418 of file predicate.c.

1419 {
1420  const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
1421  uint32 targethash;
1422 
1423  Assert(keysize == sizeof(PREDICATELOCKTAG));
1424 
1425  /* Look into the associated target object, and compute its hash code */
1426  targethash = PredicateLockTargetTagHashCode(&predicatelocktag->myTarget->tag);
1427 
1428  return PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash);
1429 }

References Assert(), sort-test::key, PREDICATELOCKTAG::myTarget, PredicateLockHashCodeFromTargetHashCode, PredicateLockTargetTagHashCode, and PREDICATELOCKTARGET::tag.

Referenced by InitPredicateLocks().

◆ predicatelock_twophase_recover()

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

Definition at line 5053 of file predicate.c.

5055 {
5056  TwoPhasePredicateRecord *record;
5057 
5058  Assert(len == sizeof(TwoPhasePredicateRecord));
5059 
5060  record = (TwoPhasePredicateRecord *) recdata;
5061 
5062  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
5063  (record->type == TWOPHASEPREDICATERECORD_LOCK));
5064 
5065  if (record->type == TWOPHASEPREDICATERECORD_XACT)
5066  {
5067  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
5068  TwoPhasePredicateXactRecord *xactRecord;
5069  SERIALIZABLEXACT *sxact;
5070  SERIALIZABLEXID *sxid;
5071  SERIALIZABLEXIDTAG sxidtag;
5072  bool found;
5073 
5074  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
5075 
5076  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
5077  sxact = CreatePredXact();
5078  if (!sxact)
5079  ereport(ERROR,
5080  (errcode(ERRCODE_OUT_OF_MEMORY),
5081  errmsg("out of shared memory")));
5082 
5083  /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
5084  sxact->vxid.backendId = InvalidBackendId;
5086  sxact->pid = 0;
5087  sxact->pgprocno = INVALID_PGPROCNO;
5088 
5089  /* a prepared xact hasn't committed yet */
5093 
5095 
5096  /*
5097  * Don't need to track this; no transactions running at the time the
5098  * recovered xact started are still active, except possibly other
5099  * prepared xacts and we don't care whether those are RO_SAFE or not.
5100  */
5102 
5103  SHMQueueInit(&(sxact->predicateLocks));
5104  SHMQueueElemInit(&(sxact->finishedLink));
5105 
5106  sxact->topXid = xid;
5107  sxact->xmin = xactRecord->xmin;
5108  sxact->flags = xactRecord->flags;
5109  Assert(SxactIsPrepared(sxact));
5110  if (!SxactIsReadOnly(sxact))
5111  {
5115  }
5116 
5117  /*
5118  * We don't know whether the transaction had any conflicts or not, so
5119  * we'll conservatively assume that it had both a conflict in and a
5120  * conflict out, and represent that with the summary conflict flags.
5121  */
5122  SHMQueueInit(&(sxact->outConflicts));
5123  SHMQueueInit(&(sxact->inConflicts));
5126 
5127  /* Register the transaction's xid */
5128  sxidtag.xid = xid;
5130  &sxidtag,
5131  HASH_ENTER, &found);
5132  Assert(sxid != NULL);
5133  Assert(!found);
5134  sxid->myXact = (SERIALIZABLEXACT *) sxact;
5135 
5136  /*
5137  * Update global xmin. Note that this is a special case compared to
5138  * registering a normal transaction, because the global xmin might go
5139  * backwards. That's OK, because until recovery is over we're not
5140  * going to complete any transactions or create any non-prepared
5141  * transactions, so there's no danger of throwing away.
5142  */
5145  {
5146  PredXact->SxactGlobalXmin = sxact->xmin;
5148  SerialSetActiveSerXmin(sxact->xmin);
5149  }
5150  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
5151  {
5154  }
5155 
5156  LWLockRelease(SerializableXactHashLock);
5157  }
5158  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
5159  {
5160  /* Lock record. Recreate the PREDICATELOCK */
5161  TwoPhasePredicateLockRecord *lockRecord;
5162  SERIALIZABLEXID *sxid;
5163  SERIALIZABLEXACT *sxact;
5164  SERIALIZABLEXIDTAG sxidtag;
5165  uint32 targettaghash;
5166 
5167  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
5168  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
5169 
5170  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
5171  sxidtag.xid = xid;
5172  sxid = (SERIALIZABLEXID *)
5173  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
5174  LWLockRelease(SerializableXactHashLock);
5175 
5176  Assert(sxid != NULL);
5177  sxact = sxid->myXact;
5178  Assert(sxact != InvalidSerializableXact);
5179 
5180  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5181  }
5182 }
#define InvalidBackendId
Definition: backendid.h:23
uint32 LocalTransactionId
Definition: c.h:589
const void size_t len
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2447
#define RecoverySerCommitSeqNo
LocalTransactionId localTransactionId
Definition: lock.h:67
BackendId backendId
Definition: lock.h:66

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, INVALID_PGPROCNO, InvalidBackendId, InvalidSerCommitSeqNo, InvalidSerializableXact, InvalidTransactionId, SERIALIZABLEXACT::lastCommitBeforeSnapshot, len, VirtualTransactionId::localTransactionId, TwoPhasePredicateRecord::lockRecord, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_prepared_xacts, MaxBackends, SERIALIZABLEXID::myXact, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, PredXact, SERIALIZABLEXACT::prepareSeqNo, RecoverySerCommitSeqNo, SERIALIZABLEXACT::SeqNo, SerializableXidHash, 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.

◆ PredicateLockAcquire()

static void PredicateLockAcquire ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2512 of file predicate.c.

2513 {
2514  uint32 targettaghash;
2515  bool found;
2516  LOCALPREDICATELOCK *locallock;
2517 
2518  /* Do we have the lock already, or a covering lock? */
2519  if (PredicateLockExists(targettag))
2520  return;
2521 
2522  if (CoarserLockCovers(targettag))
2523  return;
2524 
2525  /* the same hash and LW lock apply to the lock target and the local lock. */
2526  targettaghash = PredicateLockTargetTagHashCode(targettag);
2527 
2528  /* Acquire lock in local table */
2529  locallock = (LOCALPREDICATELOCK *)
2531  targettag, targettaghash,
2532  HASH_ENTER, &found);
2533  locallock->held = true;
2534  if (!found)
2535  locallock->childLocks = 0;
2536 
2537  /* Actually create the lock */
2538  CreatePredicateLock(targettag, targettaghash, MySerializableXact);
2539 
2540  /*
2541  * Lock has been acquired. Check whether it should be promoted to a
2542  * coarser granularity, or whether there are finer-granularity locks to
2543  * clean up.
2544  */
2545  if (CheckAndPromotePredicateLockRequest(targettag))
2546  {
2547  /*
2548  * Lock request was promoted to a coarser-granularity lock, and that
2549  * lock was acquired. It will delete this lock and any of its
2550  * children, so we're done.
2551  */
2552  }
2553  else
2554  {
2555  /* Clean up any finer-granularity locks */
2557  DeleteChildTargetLocks(targettag);
2558  }
2559 }
static void DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
Definition: predicate.c:2198
static bool CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag)
Definition: predicate.c:2320
static bool CoarserLockCovers(const PREDICATELOCKTARGETTAG *newtargettag)
Definition: predicate.c:2095

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

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

◆ PredicateLockExists()

static bool PredicateLockExists ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2029 of file predicate.c.

2030 {
2031  LOCALPREDICATELOCK *lock;
2032 
2033  /* check local hash table */
2035  targettag,
2036  HASH_FIND, NULL);
2037 
2038  if (!lock)
2039  return false;
2040 
2041  /*
2042  * Found entry in the table, but still need to check whether it's actually
2043  * held -- it could just be a parent of some held lock.
2044  */
2045  return lock->held;
2046 }

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

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

◆ PredicateLockingNeededForRelation()

static bool PredicateLockingNeededForRelation ( Relation  relation)
inlinestatic

Definition at line 495 of file predicate.c.

496 {
497  return !(relation->rd_id < FirstUnpinnedObjectId ||
498  RelationUsesLocalBuffers(relation) ||
499  relation->rd_rel->relkind == RELKIND_MATVIEW);
500 }
#define RelationUsesLocalBuffers(relation)
Definition: rel.h:622
Form_pg_class rd_rel
Definition: rel.h:109
#define FirstUnpinnedObjectId
Definition: transam.h:196

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

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

◆ PredicateLockPage()

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

◆ PredicateLockPageCombine()

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

Definition at line 3254 of file predicate.c.

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

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

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

Definition at line 3169 of file predicate.c.

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

References Assert(), BlockNumberIsValid, RelFileNode::dbNode, GetParentPredicateLockTag(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PredicateLockingNeededForRelation(), PredXact, 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().

◆ PredicateLockRelation()

void PredicateLockRelation ( Relation  relation,
Snapshot  snapshot 
)

Definition at line 2571 of file predicate.c.

2572 {
2574 
2575  if (!SerializationNeededForRead(relation, snapshot))
2576  return;
2577 
2579  relation->rd_node.dbNode,
2580  relation->rd_id);
2581  PredicateLockAcquire(&tag);
2582 }

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

Referenced by _bt_endpoint(), _bt_first(), heap_beginscan(), and index_beginscan_internal().

◆ PredicateLockShmemSize()

Size PredicateLockShmemSize ( void  )

Definition at line 1356 of file predicate.c.

1357 {
1358  Size size = 0;
1359  long max_table_size;
1360 
1361  /* predicate lock target hash table */
1362  max_table_size = NPREDICATELOCKTARGETENTS();
1363  size = add_size(size, hash_estimate_size(max_table_size,
1364  sizeof(PREDICATELOCKTARGET)));
1365 
1366  /* predicate lock hash table */
1367  max_table_size *= 2;
1368  size = add_size(size, hash_estimate_size(max_table_size,
1369  sizeof(PREDICATELOCK)));
1370 
1371  /*
1372  * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
1373  * margin.
1374  */
1375  size = add_size(size, size / 10);
1376 
1377  /* transaction list */
1378  max_table_size = MaxBackends + max_prepared_xacts;
1379  max_table_size *= 10;
1380  size = add_size(size, PredXactListDataSize);
1381  size = add_size(size, mul_size((Size) max_table_size,
1383 
1384  /* transaction xid table */
1385  size = add_size(size, hash_estimate_size(max_table_size,
1386  sizeof(SERIALIZABLEXID)));
1387 
1388  /* rw-conflict pool */
1389  max_table_size *= 5;
1390  size = add_size(size, RWConflictPoolHeaderDataSize);
1391  size = add_size(size, mul_size((Size) max_table_size,
1393 
1394  /* Head for list of finished serializable transactions. */
1395  size = add_size(size, sizeof(SHM_QUEUE));
1396 
1397  /* Shared memory structures for SLRU tracking of old committed xids. */
1398  size = add_size(size, sizeof(SerialControlData));
1400 
1401  return size;
1402 }
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:780
#define NUM_SERIAL_BUFFERS
Definition: predicate.h:31
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:156

References add_size(), hash_estimate_size(), max_prepared_xacts, MaxBackends, mul_size(), NPREDICATELOCKTARGETENTS, NUM_SERIAL_BUFFERS, PredXactListDataSize, PredXactListElementDataSize, RWConflictDataSize, RWConflictPoolHeaderDataSize, and SimpleLruShmemSize().

Referenced by CalculateShmemSize().

◆ PredicateLockTID()

void PredicateLockTID ( Relation  relation,
ItemPointer  tid,
Snapshot  snapshot,
TransactionId  tuple_xid 
)

Definition at line 2616 of file predicate.c.

2618 {
2620 
2621  if (!SerializationNeededForRead(relation, snapshot))
2622  return;
2623 
2624  /*
2625  * Return if this xact wrote it.
2626  */
2627  if (relation->rd_index == NULL)
2628  {
2629  /* If we wrote it; we already have a write lock. */
2630  if (TransactionIdIsCurrentTransactionId(tuple_xid))
2631  return;
2632  }
2633 
2634  /*
2635  * Do quick-but-not-definitive test for a relation lock first. This will
2636  * never cause a return when the relation is *not* locked, but will
2637  * occasionally let the check continue when there really *is* a relation
2638  * level lock.
2639  */
2641  relation->rd_node.dbNode,
2642  relation->rd_id);
2643  if (PredicateLockExists(&tag))
2644  return;
2645 
2647  relation->rd_node.dbNode,
2648  relation->rd_id,
2651  PredicateLockAcquire(&tag);
2652 }
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:922

References RelFileNode::dbNode, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, PredicateLockAcquire(), PredicateLockExists(), RelationData::rd_id, RelationData::rd_index, RelationData::rd_node, SerializationNeededForRead(), SET_PREDICATELOCKTARGETTAG_RELATION, SET_PREDICATELOCKTARGETTAG_TUPLE, and TransactionIdIsCurrentTransactionId().

Referenced by heap_fetch(), heap_hot_search_buffer(), and heapam_scan_bitmap_next_block().

◆ PredicateLockTwoPhaseFinish()

void PredicateLockTwoPhaseFinish ( TransactionId  xid,
bool  isCommit 
)

Definition at line 5026 of file predicate.c.

5027 {
5028  SERIALIZABLEXID *sxid;
5029  SERIALIZABLEXIDTAG sxidtag;
5030 
5031  sxidtag.xid = xid;
5032 
5033  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
5034  sxid = (SERIALIZABLEXID *)
5035  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
5036  LWLockRelease(SerializableXactHashLock);
5037 
5038  /* xid will not be found if it wasn't a serializable transaction */
5039  if (sxid == NULL)
5040  return;
5041 
5042  /* Release its locks */
5043  MySerializableXact = sxid->myXact;
5044  MyXactDidWrite = true; /* conservatively assume that we wrote
5045  * something */
5046  ReleasePredicateLocks(isCommit, false);
5047 }

References HASH_FIND, hash_search(), LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXID::myXact, MyXactDidWrite, ReleasePredicateLocks(), SerializableXidHash, and SERIALIZABLEXIDTAG::xid.

Referenced by FinishPreparedTransaction().

◆ RegisterPredicateLockingXid()

void RegisterPredicateLockingXid ( TransactionId  xid)

Definition at line 1943 of file predicate.c.

1944 {
1945  SERIALIZABLEXIDTAG sxidtag;
1946  SERIALIZABLEXID *sxid;
1947  bool found;
1948 
1949  /*
1950  * If we're not tracking predicate lock data for this transaction, we
1951  * should ignore the request and return quickly.
1952  */
1954  return;
1955 
1956  /* We should have a valid XID and be at the top level. */
1958 
1959  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1960 
1961  /* This should only be done once per transaction. */
1963 
1964  MySerializableXact->topXid = xid;
1965 
1966  sxidtag.xid = xid;
1968  &sxidtag,
1969  HASH_ENTER, &found);
1970  Assert(!found);
1971 
1972  /* Initialize the structure. */
1973  sxid->myXact = MySerializableXact;
1974  LWLockRelease(SerializableXactHashLock);
1975 }

References Assert(), HASH_ENTER, hash_search(), InvalidSerializableXact, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXID::myXact, SerializableXidHash, SERIALIZABLEXACT::topXid, TransactionIdIsValid, and SERIALIZABLEXIDTAG::xid.

Referenced by AssignTransactionId().

◆ ReleaseOneSerializableXact()

static void ReleaseOneSerializableXact ( SERIALIZABLEXACT sxact,
bool  partial,
bool  summarize 
)
static

Definition at line 3902 of file predicate.c.

3904 {
3905  PREDICATELOCK *predlock;
3906  SERIALIZABLEXIDTAG sxidtag;
3907  RWConflict conflict,
3908  nextConflict;
3909 
3910  Assert(sxact != NULL);
3911  Assert(SxactIsRolledBack(sxact) || SxactIsCommitted(sxact));
3912  Assert(partial || !SxactIsOnFinishedList(sxact));
3913  Assert(LWLockHeldByMe(SerializableFinishedListLock));
3914 
3915  /*
3916  * First release all the predicate locks held by this xact (or transfer
3917  * them to OldCommittedSxact if summarize is true)
3918  */
3919  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
3920  if (IsInParallelMode())
3922  predlock = (PREDICATELOCK *)
3923  SHMQueueNext(&(sxact->predicateLocks),
3924  &(sxact->predicateLocks),
3925  offsetof(PREDICATELOCK, xactLink));
3926  while (predlock)
3927  {
3928  PREDICATELOCK *nextpredlock;
3929  PREDICATELOCKTAG tag;
3930  SHM_QUEUE *targetLink;
3931  PREDICATELOCKTARGET *target;
3932  PREDICATELOCKTARGETTAG targettag;
3933  uint32 targettaghash;
3934  LWLock *partitionLock;
3935 
3936  nextpredlock = (PREDICATELOCK *)
3937  SHMQueueNext(&(sxact->predicateLocks),
3938  &(predlock->xactLink),
3939  offsetof(PREDICATELOCK, xactLink));
3940 
3941  tag = predlock->tag;
3942  targetLink = &(predlock->targetLink);
3943  target = tag.myTarget;
3944  targettag = target->tag;
3945  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3946  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3947 
3948  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3949 
3950  SHMQueueDelete(targetLink);
3951 
3954  targettaghash),
3955  HASH_REMOVE, NULL);
3956  if (summarize)
3957  {
3958  bool found;
3959 
3960  /* Fold into dummy transaction list. */
3961  tag.myXact = OldCommittedSxact;
3964  targettaghash),
3965  HASH_ENTER_NULL, &found);
3966  if (!predlock)
3967  ereport(ERROR,
3968  (errcode(ERRCODE_OUT_OF_MEMORY),
3969  errmsg("out of shared memory"),
3970  errhint("You might need to increase max_pred_locks_per_transaction.")));
3971  if (found)
3972  {
3973  Assert(predlock->commitSeqNo != 0);
3975  if (predlock->commitSeqNo < sxact->commitSeqNo)
3976  predlock->commitSeqNo = sxact->commitSeqNo;
3977  }
3978  else
3979  {
3981  &(predlock->targetLink));
3983  &(predlock->xactLink));
3984  predlock->commitSeqNo = sxact->commitSeqNo;
3985  }
3986  }
3987  else
3988  RemoveTargetIfNoLongerUsed(target, targettaghash);
3989 
3990  LWLockRelease(partitionLock);
3991 
3992  predlock = nextpredlock;
3993  }
3994 
3995  /*
3996  * Rather than retail removal, just re-init the head after we've run
3997  * through the list.
3998  */
3999  SHMQueueInit(&sxact->predicateLocks);
4000 
4001  if (IsInParallelMode())
4003  LWLockRelease(SerializablePredicateListLock);
4004 
4005  sxidtag.xid = sxact->topXid;
4006  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4007 
4008  /* Release all outConflicts (unless 'partial' is true) */
4009  if (!partial)
4010  {
4011  conflict = (RWConflict)
4012  SHMQueueNext(&sxact->outConflicts,
4013  &sxact->outConflicts,
4014  offsetof(RWConflictData, outLink));
4015  while (conflict)
4016  {
4017  nextConflict = (RWConflict)
4018  SHMQueueNext(&sxact->outConflicts,
4019  &conflict->outLink,
4020  offsetof(RWConflictData, outLink));
4021  if (summarize)
4023  ReleaseRWConflict(conflict);
4024  conflict = nextConflict;
4025  }
4026  }
4027 
4028  /* Release all inConflicts. */
4029  conflict = (RWConflict)
4030  SHMQueueNext(&sxact->inConflicts,
4031  &sxact->inConflicts,
4032  offsetof(RWConflictData, inLink));
4033  while (conflict)
4034  {
4035  nextConflict = (RWConflict)
4036  SHMQueueNext(&sxact->inConflicts,
4037  &conflict->inLink,
4038  offsetof(RWConflictData, inLink));
4039  if (summarize)
4041  ReleaseRWConflict(conflict);
4042  conflict = nextConflict;
4043  }
4044 
4045  /* Finally, get rid of the xid and the record of the transaction itself. */
4046  if (!partial)
4047  {
4048  if (sxidtag.xid != InvalidTransactionId)
4049  hash_search(SerializableXidHash, &sxidtag, HASH_REMOVE, NULL);
4050  ReleasePredXact(sxact);
4051  }
4052 
4053  LWLockRelease(SerializableXactHashLock);
4054 }
#define SxactIsOnFinishedList(sxact)
Definition: predicate.c:262
#define SxactIsRolledBack(sxact)
Definition: predicate.c:274

References Assert(), SERIALIZABLEXACT::commitSeqNo, PREDICATELOCK::commitSeqNo, ereport, errcode(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, HASH_ENTER_NULL, HASH_REMOVE, hash_search(), hash_search_with_hash_value(), SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, InvalidSerCommitSeqNo, InvalidTransactionId, IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, offsetof, OldCommittedSxact, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::perXactPredicateListLock, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetTagHashCode, ReleasePredXact(), ReleaseRWConflict(), RemoveTargetIfNoLongerUsed(), SerializableXidHash, SHMQueueDelete(), SHMQueueInit(), SHMQueueInsertBefore(), SHMQueueNext(), SXACT_FLAG_SUMMARY_CONFLICT_IN, SXACT_FLAG_SUMMARY_CONFLICT_OUT, RWConflictData::sxactIn, SxactIsCommitted, SxactIsOnFinishedList, SxactIsRolledBack, RWConflictData::sxactOut, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, SERIALIZABLEXACT::topXid, PREDICATELOCK::xactLink, and SERIALIZABLEXIDTAG::xid.

Referenced by ClearOldPredicateLocks(), ReleasePredicateLocks(), and SummarizeOldestCommittedSxact().

◆ ReleasePredicateLocks()

void ReleasePredicateLocks ( bool  isCommit,
bool  isReadOnlySafe 
)

Definition at line 3334 of file predicate.c.

3335 {
3336  bool needToClear;
3337  RWConflict conflict,
3338  nextConflict,
3339  possibleUnsafeConflict;
3340  SERIALIZABLEXACT *roXact;
3341 
3342  /*
3343  * We can't trust XactReadOnly here, because a transaction which started
3344  * as READ WRITE can show as READ ONLY later, e.g., within
3345  * subtransactions. We want to flag a transaction as READ ONLY if it
3346  * commits without writing so that de facto READ ONLY transactions get the
3347  * benefit of some RO optimizations, so we will use this local variable to
3348  * get some cleanup logic right which is based on whether the transaction
3349  * was declared READ ONLY at the top level.
3350  */
3351  bool topLevelIsDeclaredReadOnly;
3352 
3353  /* We can't be both committing and releasing early due to RO_SAFE. */
3354  Assert(!(isCommit && isReadOnlySafe));
3355 
3356  /* Are we at the end of a transaction, that is, a commit or abort? */
3357  if (!isReadOnlySafe)
3358  {
3359  /*
3360  * Parallel workers mustn't release predicate locks at the end of
3361  * their transaction. The leader will do that at the end of its
3362  * transaction.
3363  */
3364  if (IsParallelWorker())
3365  {
3367  return;
3368  }
3369 
3370  /*
3371  * By the time the leader in a parallel query reaches end of
3372  * transaction, it has waited for all workers to exit.
3373  */
3375 
3376  /*
3377  * If the leader in a parallel query earlier stashed a partially
3378  * released SERIALIZABLEXACT for final clean-up at end of transaction
3379  * (because workers might still have been accessing it), then it's
3380  * time to restore it.
3381  */
3383  {
3388  }
3389  }
3390 
3392  {
3393  Assert(LocalPredicateLockHash == NULL);
3394  return;
3395  }
3396 
3397  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3398 
3399  /*
3400  * If the transaction is committing, but it has been partially released
3401  * already, then treat this as a roll back. It was marked as rolled back.
3402  */
3404  isCommit = false;
3405 
3406  /*
3407  * If we're called in the middle of a transaction because we discovered
3408  * that the SXACT_FLAG_RO_SAFE flag was set, then we'll partially release
3409  * it (that is, release the predicate locks and conflicts, but not the
3410  * SERIALIZABLEXACT itself) if we're the first backend to have noticed.
3411  */
3412  if (isReadOnlySafe && IsInParallelMode())
3413  {
3414  /*
3415  * The leader needs to stash a pointer to it, so that it can
3416  * completely release it at end-of-transaction.
3417  */
3418  if (!IsParallelWorker())
3420 
3421  /*
3422  * The first backend to reach this condition will partially release
3423  * the SERIALIZABLEXACT. All others will just clear their
3424  * backend-local state so that they stop doing SSI checks for the rest
3425  * of the transaction.
3426  */
3428  {
3429  LWLockRelease(SerializableXactHashLock);
3431  return;
3432  }
3433  else
3434  {
3436  /* ... and proceed to perform the partial release below. */
3437  }
3438  }
3439  Assert(!isCommit || SxactIsPrepared(MySerializableXact));
3440  Assert(!isCommit || !SxactIsDoomed(MySerializableXact));
3444 
3445  /* may not be serializable during COMMIT/ROLLBACK PREPARED */
3447 
3448  /* We'd better not already be on the cleanup list. */
3450 
3451  topLevelIsDeclaredReadOnly = SxactIsReadOnly(MySerializableXact);
3452 
3453  /*
3454  * We don't hold XidGenLock lock here, assuming that TransactionId is
3455  * atomic!
3456  *
3457  * If this value is changing, we don't care that much whether we get the
3458  * old or new value -- it is just used to determine how far
3459  * SxactGlobalXmin must advance before this transaction can be fully
3460  * cleaned up. The worst that could happen is we wait for one more
3461  * transaction to complete before freeing some RAM; correctness of visible
3462  * behavior is not affected.
3463  */
3465 
3466  /*
3467  * If it's not a commit it's either a rollback or a read-only transaction
3468  * flagged SXACT_FLAG_RO_SAFE, and we can clear our locks immediately.
3469  */
3470  if (isCommit)
3471  {
3474  /* Recognize implicit read-only transaction (commit without write). */
3475  if (!MyXactDidWrite)
3477  }
3478  else
3479  {
3480  /*
3481  * The DOOMED flag indicates that we intend to roll back this
3482  * transaction and so it should not cause serialization failures for
3483  * other transactions that conflict with it. Note that this flag might
3484  * already be set, if another backend marked this transaction for
3485  * abort.
3486  *
3487  * The ROLLED_BACK flag further indicates that ReleasePredicateLocks
3488  * has been called, and so the SerializableXact is eligible for
3489  * cleanup. This means it should not be considered when calculating
3490  * SxactGlobalXmin.
3491  */
3494 
3495  /*
3496  * If the transaction was previously prepared, but is now failing due
3497  * to a ROLLBACK PREPARED or (hopefully very rare) error after the
3498  * prepare, clear the prepared flag. This simplifies conflict
3499  * checking.
3500  */
3502  }
3503 
3504  if (!topLevelIsDeclaredReadOnly)
3505  {
3507  if (--(PredXact->WritableSxactCount) == 0)
3508  {
3509  /*
3510  * Release predicate locks and rw-conflicts in for all committed
3511  * transactions. There are no longer any transactions which might
3512  * conflict with the locks and no chance for new transactions to
3513  * overlap. Similarly, existing conflicts in can't cause pivots,
3514  * and any conflicts in which could have completed a dangerous
3515  * structure would already have caused a rollback, so any
3516  * remaining ones must be benign.
3517  */
3519  }
3520  }
3521  else
3522  {
3523  /*
3524  * Read-only transactions: clear the list of transactions that might
3525  * make us unsafe. Note that we use 'inLink' for the iteration as
3526  * opposed to 'outLink' for the r/w xacts.
3527  */
3528  possibleUnsafeConflict = (RWConflict)
3531  offsetof(RWConflictData, inLink));
3532  while (possibleUnsafeConflict)
3533  {
3534  nextConflict = (RWConflict)
3536  &possibleUnsafeConflict->inLink,
3537  offsetof(RWConflictData, inLink));
3538 
3539  Assert(!SxactIsReadOnly(possibleUnsafeConflict->sxactOut));
3540  Assert(MySerializableXact == possibleUnsafeConflict->sxactIn);
3541 
3542  ReleaseRWConflict(possibleUnsafeConflict);
3543 
3544  possibleUnsafeConflict = nextConflict;
3545  }
3546  }
3547 
3548  /* Check for conflict out to old committed transactions. */
3549  if (isCommit
3552  {
3553  /*
3554  * we don't know which old committed transaction we conflicted with,
3555  * so be conservative and use FirstNormalSerCommitSeqNo here
3556  */
3560  }
3561 
3562  /*
3563  * Release all outConflicts to committed transactions. If we're rolling
3564  * back clear them all. Set SXACT_FLAG_CONFLICT_OUT if any point to
3565  * previously committed transactions.
3566  */
3567  conflict = (RWConflict)
3570  offsetof(RWConflictData, outLink));
3571  while (conflict)
3572  {
3573  nextConflict = (RWConflict)
3575  &conflict->outLink,
3576  offsetof(RWConflictData, outLink));
3577 
3578  if (isCommit
3580  && SxactIsCommitted(conflict->sxactIn))
3581  {
3586  }
3587 
3588  if (!isCommit
3589  || SxactIsCommitted(conflict->sxactIn)
3591  ReleaseRWConflict(conflict);
3592 
3593  conflict = nextConflict;
3594  }
3595 
3596  /*
3597  * Release all inConflicts from committed and read-only transactions. If
3598  * we're rolling back, clear them all.
3599  */
3600  conflict = (RWConflict)
3603  offsetof(RWConflictData, inLink));
3604  while (conflict)
3605  {
3606  nextConflict = (RWConflict)
3608  &conflict->inLink,
3609  offsetof(RWConflictData, inLink));
3610 
3611  if (!isCommit
3612  || SxactIsCommitted(conflict->sxactOut)
3613  || SxactIsReadOnly(conflict->sxactOut))
3614  ReleaseRWConflict(conflict);
3615 
3616  conflict = nextConflict;
3617  }
3618 
3619  if (!topLevelIsDeclaredReadOnly)
3620  {
3621  /*
3622  * Remove ourselves from the list of possible conflicts for concurrent
3623  * READ ONLY transactions, flagging them as unsafe if we have a
3624  * conflict out. If any are waiting DEFERRABLE transactions, wake them
3625  * up if they are known safe or known unsafe.
3626  */
3627  possibleUnsafeConflict = (RWConflict)
3630  offsetof(RWConflictData, outLink));
3631  while (possibleUnsafeConflict)
3632  {
3633  nextConflict = (RWConflict)
3635  &possibleUnsafeConflict->outLink,
3636  offsetof(RWConflictData, outLink));
3637 
3638  roXact = possibleUnsafeConflict->sxactIn;
3639  Assert(MySerializableXact == possibleUnsafeConflict->sxactOut);
3640  Assert(SxactIsReadOnly(roXact));
3641 
3642  /* Mark conflicted if necessary. */
3643  if (isCommit
3644  && MyXactDidWrite
3647  <= roXact->SeqNo.lastCommitBeforeSnapshot))
3648  {
3649  /*
3650  * This releases possibleUnsafeConflict (as well as all other
3651  * possible conflicts for roXact)
3652  */
3653  FlagSxactUnsafe(roXact);
3654  }
3655  else
3656  {
3657  ReleaseRWConflict(possibleUnsafeConflict);
3658 
3659  /*
3660  * If we were the last possible conflict, flag it safe. The
3661  * transaction can now safely release its predicate locks (but
3662  * that transaction's backend has to do that itself).
3663  */
3664  if (SHMQueueEmpty(&roXact->possibleUnsafeConflicts))
3665  roXact->flags |= SXACT_FLAG_RO_SAFE;
3666  }
3667 
3668  /*
3669  * Wake up the process for a waiting DEFERRABLE transaction if we
3670  * now know it's either safe or conflicted.
3671  */
3672  if (SxactIsDeferrableWaiting(roXact) &&
3673  (SxactIsROUnsafe(roXact) || SxactIsROSafe(roXact)))
3674  ProcSendSignal(roXact->pgprocno);
3675 
3676  possibleUnsafeConflict = nextConflict;
3677  }
3678  }
3679 
3680  /*
3681  * Check whether it's time to clean up old transactions. This can only be
3682  * done when the last serializable transaction with the oldest xmin among
3683  * serializable transactions completes. We then find the "new oldest"
3684  * xmin and purge any transactions which finished before this transaction
3685  * was launched.
3686  */
3687  needToClear = false;
3689  {
3691  if (--(PredXact->SxactGlobalXminCount) == 0)
3692  {
3694  needToClear = true;
3695  }
3696  }
3697 
3698  LWLockRelease(SerializableXactHashLock);
3699 
3700  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3701 
3702  /* Add this to the list of transactions to check for later cleanup. */
3703  if (isCommit)
3706 
3707  /*
3708  * If we're releasing a RO_SAFE transaction in parallel mode, we'll only
3709  * partially release it. That's necessary because other backends may have
3710  * a reference to it. The leader will release the SERIALIZABLEXACT itself
3711  * at the end of the transaction after workers have stopped running.
3712  */
3713  if (!isCommit)
3715  isReadOnlySafe && IsInParallelMode(),
3716  false);
3717 
3718  LWLockRelease(SerializableFinishedListLock);
3719 
3720  if (needToClear)
3722 
3724 }
static void SetNewSxactGlobalXmin(void)
Definition: predicate.c:3276
static void ReleasePredicateLocksLocal(void)
Definition: predicate.c:3727
static void ClearOldPredicateLocks(void)
Definition: predicate.c:3745
static void FlagSxactUnsafe(SERIALIZABLEXACT *sxact)
Definition: predicate.c:750
static SERIALIZABLEXACT * SavedSerializableXact
Definition: predicate.c:426
#define SXACT_FLAG_CONFLICT_OUT
#define SXACT_FLAG_ROLLED_BACK
#define SXACT_FLAG_PARTIALLY_RELEASED
#define SXACT_FLAG_RO_SAFE
void ProcSendSignal(int pgprocno)
Definition: proc.c:1885
FullTransactionId nextXid
Definition: transam.h:220
#define XidFromFullTransactionId(x)
Definition: transam.h:48
VariableCache ShmemVariableCache
Definition: varsup.c:34

References Assert(), PredXactListData::CanPartialClearThrough, ClearOldPredicateLocks(), SERIALIZABLEXACT::commitSeqNo, SERIALIZABLEXACT::earliestOutConflictCommit, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, FirstNormalSerCommitSeqNo, SERIALIZABLEXACT::flags, FlagSxactUnsafe(), SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, InvalidSerializableXact, IsInParallelMode(), IsolationIsSerializable, IsParallelWorker, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, LocalPredicateLockHash, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, MyXactDidWrite, VariableCacheData::nextXid, offsetof, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, ParallelContextActive(), SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, PredXact, SERIALIZABLEXACT::prepareSeqNo, ProcSendSignal(), ReleaseOneSerializableXact(), ReleasePredicateLocksLocal(), ReleaseRWConflict(), SavedSerializableXact, SERIALIZABLEXACT::SeqNo, SetNewSxactGlobalXmin(), ShmemVariableCache, SHMQueueEmpty(), SHMQueueInsertBefore(), SHMQueueNext(), SXACT_FLAG_COMMITTED, SXACT_FLAG_CONFLICT_OUT, SXACT_FLAG_DOOMED, SXACT_FLAG_PARTIALLY_RELEASED, SXACT_FLAG_PREPARED, SXACT_FLAG_READ_ONLY, SXACT_FLAG_RO_SAFE, SXACT_FLAG_ROLLED_BACK, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactHasConflictOut, SxactHasSummaryConflictOut, RWConflictData::sxactIn, SxactIsCommitted, SxactIsDeferrableWaiting, SxactIsDoomed, SxactIsOnFinishedList, SxactIsPartiallyReleased, SxactIsPrepared, SxactIsReadOnly, SxactIsRolledBack, SxactIsROSafe, SxactIsROUnsafe, RWConflictData::sxactOut, TransactionIdEquals, PredXactListData::WritableSxactCount, XidFromFullTransactionId, and SERIALIZABLEXACT::xmin.

Referenced by GetSafeSnapshot(), PredicateLockTwoPhaseFinish(), ResourceOwnerReleaseInternal(), and SerializationNeededForRead().

◆ ReleasePredicateLocksLocal()

static void ReleasePredicateLocksLocal ( void  )
static

Definition at line 3727 of file predicate.c.

3728 {
3730  MyXactDidWrite = false;
3731 
3732  /* Delete per-transaction lock table */
3733  if (LocalPredicateLockHash != NULL)
3734  {
3736  LocalPredicateLockHash = NULL;
3737  }
3738 }

References hash_destroy(), InvalidSerializableXact, LocalPredicateLockHash, MySerializableXact, and MyXactDidWrite.

Referenced by ReleasePredicateLocks().

◆ ReleasePredXact()

static void ReleasePredXact ( SERIALIZABLEXACT sxact)
static

◆ ReleaseRWConflict()

static void ReleaseRWConflict ( RWConflict  conflict)
static

◆ RemoveScratchTarget()

static void RemoveScratchTarget ( bool  lockheld)
static

Definition at line 2124 of file predicate.c.

2125 {
2126  bool found;
2127 
2128  Assert(LWLockHeldByMe(SerializablePredicateListLock));
2129 
2130  if (!lockheld)
2135  HASH_REMOVE, &found);
2136  Assert(found);
2137  if (!lockheld)
2139 }

References Assert(), HASH_REMOVE, hash_search_with_hash_value(), LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), PredicateLockTargetHash, ScratchPartitionLock, ScratchTargetTag, and ScratchTargetTagHash.

Referenced by DropAllPredicateLocksFromTable(), and TransferPredicateLocksToNewTarget().

◆ RemoveTargetIfNoLongerUsed()

static void RemoveTargetIfNoLongerUsed ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

Definition at line 2167 of file predicate.c.

2168 {
2170 
2171  Assert(LWLockHeldByMe(SerializablePredicateListLock));
2172 
2173  /* Can't remove it until no locks at this target. */
2174  if (!SHMQueueEmpty(&target->predicateLocks))
2175  return;
2176 
2177  /* Actually remove the target. */
2179  &target->tag,
2180  targettaghash,
2181  HASH_REMOVE, NULL);
2182  Assert(rmtarget == target);
2183 }

References Assert(), HASH_REMOVE, hash_search_with_hash_value(), LWLockHeldByMe(), PG_USED_FOR_ASSERTS_ONLY, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, SHMQueueEmpty(), and PREDICATELOCKTARGET::tag.

Referenced by CheckTargetForConflictsIn(), ClearOldPredicateLocks(), DeleteChildTargetLocks(), DeleteLockTarget(), ReleaseOneSerializableXact(), and TransferPredicateLocksToNewTarget().

◆ RestoreScratchTarget()

static void RestoreScratchTarget ( bool  lockheld)
static

Definition at line 2145 of file predicate.c.

2146 {
2147  bool found;
2148 
2149  Assert(LWLockHeldByMe(SerializablePredicateListLock));
2150 
2151  if (!lockheld)
2156  HASH_ENTER, &found);
2157  Assert(!found);
2158  if (!lockheld)
2160 }

References Assert(), HASH_ENTER, hash_search_with_hash_value(), LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), PredicateLockTargetHash, ScratchPartitionLock, ScratchTargetTag, and ScratchTargetTagHash.

Referenced by DropAllPredicateLocksFromTable(), and TransferPredicateLocksToNewTarget().

◆ RWConflictExists()

static bool RWConflictExists ( const SERIALIZABLEXACT reader,
const SERIALIZABLEXACT writer 
)
static

Definition at line 653 of file predicate.c.

654 {
655  RWConflict conflict;
656 
657  Assert(reader != writer);
658 
659  /* Check the ends of the purported conflict first. */
660  if (SxactIsDoomed(reader)
661  || SxactIsDoomed(writer)
662  || SHMQueueEmpty(&reader->outConflicts)
663  || SHMQueueEmpty(&writer->inConflicts))
664  return false;
665 
666  /* A conflict is possible; walk the list to find out. */
667  conflict = (RWConflict)
668  SHMQueueNext(&reader->outConflicts,
669  &reader->outConflicts,
670  offsetof(RWConflictData, outLink));
671  while (conflict)
672  {
673  if (conflict->sxactIn == writer)
674  return true;
675  conflict = (RWConflict)
676  SHMQueueNext(&reader->outConflicts,
677  &conflict->outLink,
678  offsetof(RWConflictData, outLink));
679  }
680 
681  /* No conflict found. */
682  return false;
683 }

References Assert(), SERIALIZABLEXACT::inConflicts, offsetof, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SHMQueueEmpty(), SHMQueueNext(), RWConflictData::sxactIn, and SxactIsDoomed.

Referenced by CheckForSerializableConflictOut(), CheckTableForSerializableConflictIn(), CheckTargetForConflictsIn(), and SetRWConflict().

◆ SerialAdd()

static void SerialAdd ( TransactionId  xid,
SerCommitSeqNo  minConflictCommitSeqNo 
)
static

Definition at line 906 of file predicate.c.

907 {
908  TransactionId tailXid;
909  int targetPage;
910  int slotno;
911  int firstZeroPage;
912  bool isNewPage;
913 
915 
916  targetPage = SerialPage(xid);
917 
918  LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
919 
920  /*
921  * If no serializable transactions are active, there shouldn't be anything
922  * to push out to the SLRU. Hitting this assert would mean there's
923  * something wrong with the earlier cleanup logic.
924  */
925  tailXid = serialControl->tailXid;
926  Assert(TransactionIdIsValid(tailXid));
927 
928  /*
929  * If the SLRU is currently unused, zero out the whole active region from
930  * tailXid to headXid before taking it into use. Otherwise zero out only
931  * any new pages that enter the tailXid-headXid range as we advance
932  * headXid.
933  */
934  if (serialControl->headPage < 0)
935  {
936  firstZeroPage = SerialPage(tailXid);
937  isNewPage = true;
938  }
939  else
940  {
941  firstZeroPage = SerialNextPage(serialControl->headPage);
943  targetPage);
944  }
945 
948  serialControl->headXid = xid;
949  if (isNewPage)
950  serialControl->headPage = targetPage;
951 
952  if (isNewPage)
953  {
954  /* Initialize intervening pages. */
955  while (firstZeroPage != targetPage)
956  {
957  (void) SimpleLruZeroPage(SerialSlruCtl, firstZeroPage);
958  firstZeroPage = SerialNextPage(firstZeroPage);
959  }
960  slotno = SimpleLruZeroPage(SerialSlruCtl, targetPage);
961  }
962  else
963  slotno = SimpleLruReadPage(SerialSlruCtl, targetPage, true, xid);
964 
965  SerialValue(slotno, xid) = minConflictCommitSeqNo;
966  SerialSlruCtl->shared->page_dirty[slotno] = true;
967 
968  LWLockRelease(SerialSLRULock);
969 }
uint32 TransactionId
Definition: c.h:587
#define SerialNextPage(page)
Definition: predicate.c:332
#define SerialValue(slotno, xid)
Definition: predicate.c:334
static bool SerialPagePrecedesLogically(int page1, int page2)
Definition: predicate.c:791
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:280
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:395
TransactionId headXid
Definition: predicate.c:343

References Assert(), SerialControlData::headPage, SerialControlData::headXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), serialControl, SerialNextPage, SerialPage, SerialPagePrecedesLogically(), SerialSlruCtl, SerialValue, SimpleLruReadPage(), SimpleLruZeroPage(), SerialControlData::tailXid, TransactionIdFollows(), and TransactionIdIsValid.

Referenced by SummarizeOldestCommittedSxact().

◆ SerialGetMinConflictCommitSeqNo()

static SerCommitSeqNo SerialGetMinConflictCommitSeqNo ( TransactionId  xid)
static

Definition at line 977 of file predicate.c.

978 {
979  TransactionId headXid;
980  TransactionId tailXid;
982  int slotno;
983 
985 
986  LWLockAcquire(SerialSLRULock, LW_SHARED);
987  headXid = serialControl->headXid;
988  tailXid = serialControl->tailXid;
989  LWLockRelease(SerialSLRULock);
990 
991  if (!TransactionIdIsValid(headXid))
992  return 0;
993 
994  Assert(TransactionIdIsValid(tailXid));
995 
996  if (TransactionIdPrecedes(xid, tailXid)
997  || TransactionIdFollows(xid, headXid))
998  return 0;
999 
1000  /*
1001  * The following function must be called without holding SerialSLRULock,
1002  * but will return with that lock held, which must then be released.
1003  */
1005  SerialPage(xid), xid);
1006  val =