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 "port/pg_lfind.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 origSnapshot)
 
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 260 of file predicate.c.

◆ PredicateLockHashCodeFromTargetHashCode

#define PredicateLockHashCodeFromTargetHashCode (   predicatelocktag,
  targethash 
)
Value:
((targethash) ^ ((uint32) PointerGetDatum((predicatelocktag)->myXact)) \
unsigned int uint32
Definition: c.h:442
#define LOG2_NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:98
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:670

Definition at line 312 of file predicate.c.

◆ PredicateLockHashPartition

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

Definition at line 252 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:105
LWLock lock
Definition: lwlock.h:65

Definition at line 254 of file predicate.c.

◆ PredicateLockHashPartitionLockByIndex

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

Definition at line 257 of file predicate.c.

◆ PredicateLockTargetTagHashCode

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

Definition at line 299 of file predicate.c.

◆ SERIAL_ENTRIESPERPAGE

#define SERIAL_ENTRIESPERPAGE   (SERIAL_PAGESIZE / SERIAL_ENTRYSIZE)

Definition at line 326 of file predicate.c.

◆ SERIAL_ENTRYSIZE

#define SERIAL_ENTRYSIZE   sizeof(SerCommitSeqNo)

Definition at line 325 of file predicate.c.

◆ SERIAL_MAX_PAGE

#define SERIAL_MAX_PAGE   (MaxTransactionId / SERIAL_ENTRIESPERPAGE)

Definition at line 331 of file predicate.c.

◆ SERIAL_PAGESIZE

#define SERIAL_PAGESIZE   BLCKSZ

Definition at line 324 of file predicate.c.

◆ SerialNextPage

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

Definition at line 333 of file predicate.c.

◆ SerialPage

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

Definition at line 339 of file predicate.c.

◆ SerialSlruCtl

#define SerialSlruCtl   (&SerialSlruCtlData)

Definition at line 322 of file predicate.c.

◆ SerialValue

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

Definition at line 335 of file predicate.c.

◆ SxactHasConflictOut

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

Definition at line 285 of file predicate.c.

◆ SxactHasSummaryConflictIn

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

Definition at line 278 of file predicate.c.

◆ SxactHasSummaryConflictOut

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

Definition at line 279 of file predicate.c.

◆ SxactIsCommitted

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

Definition at line 273 of file predicate.c.

◆ SxactIsDeferrableWaiting

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

Definition at line 286 of file predicate.c.

◆ SxactIsDoomed

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

Definition at line 276 of file predicate.c.

◆ SxactIsOnFinishedList

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

Definition at line 263 of file predicate.c.

◆ SxactIsPartiallyReleased

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

Definition at line 289 of file predicate.c.

◆ SxactIsPrepared

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

Definition at line 274 of file predicate.c.

◆ SxactIsReadOnly

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

Definition at line 277 of file predicate.c.

◆ SxactIsRolledBack

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

Definition at line 275 of file predicate.c.

◆ SxactIsROSafe

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

Definition at line 287 of file predicate.c.

◆ SxactIsROUnsafe

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

Definition at line 288 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 229 of file predicate.c.

Typedef Documentation

◆ SerialControl

Definition at line 348 of file predicate.c.

◆ SerialControlData

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4920 of file predicate.c.

4921 {
4922  PREDICATELOCK *predlock;
4923  SERIALIZABLEXACT *sxact;
4924  TwoPhasePredicateRecord record;
4925  TwoPhasePredicateXactRecord *xactRecord;
4926  TwoPhasePredicateLockRecord *lockRecord;
4927 
4928  sxact = MySerializableXact;
4929  xactRecord = &(record.data.xactRecord);
4930  lockRecord = &(record.data.lockRecord);
4931 
4933  return;
4934 
4935  /* Generate an xact record for our SERIALIZABLEXACT */
4937  xactRecord->xmin = MySerializableXact->xmin;
4938  xactRecord->flags = MySerializableXact->flags;
4939 
4940  /*
4941  * Note that we don't include the list of conflicts in our out in the
4942  * statefile, because new conflicts can be added even after the
4943  * transaction prepares. We'll just make a conservative assumption during
4944  * recovery instead.
4945  */
4946 
4948  &record, sizeof(record));
4949 
4950  /*
4951  * Generate a lock record for each lock.
4952  *
4953  * To do this, we need to walk the predicate lock list in our sxact rather
4954  * than using the local predicate lock table because the latter is not
4955  * guaranteed to be accurate.
4956  */
4957  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4958 
4959  /*
4960  * No need to take sxact->perXactPredicateListLock in parallel mode
4961  * because there cannot be any parallel workers running while we are
4962  * preparing a transaction.
4963  */
4965 
4966  predlock = (PREDICATELOCK *)
4967  SHMQueueNext(&(sxact->predicateLocks),
4968  &(sxact->predicateLocks),
4969  offsetof(PREDICATELOCK, xactLink));
4970 
4971  while (predlock != NULL)
4972  {
4974  lockRecord->target = predlock->tag.myTarget->tag;
4975 
4977  &record, sizeof(record));
4978 
4979  predlock = (PREDICATELOCK *)
4980  SHMQueueNext(&(sxact->predicateLocks),
4981  &(predlock->xactLink),
4982  offsetof(PREDICATELOCK, xactLink));
4983  }
4984 
4985  LWLockRelease(SerializablePredicateListLock);
4986 }
bool ParallelContextActive(void)
Definition: parallel.c:1001
#define IsParallelWorker()
Definition: parallel.h:61
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1194
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1802
@ LW_SHARED
Definition: lwlock.h:113
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:417
@ 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::@108 data
TwoPhasePredicateLockRecord lockRecord
TwoPhasePredicateXactRecord xactRecord
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1257
#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, 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 5192 of file predicate.c.

5193 {
5194 
5196 
5197  MySerializableXact = (SERIALIZABLEXACT *) handle;
5200 }
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:953
@ HASH_ENTER
Definition: hsearch.h:114
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2512
static HTAB * LocalPredicateLockHash
Definition: predicate.c:410
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 4441 of file predicate.c.

4442 {
4443  PREDICATELOCKTARGETTAG targettag;
4444 
4445  if (!SerializationNeededForWrite(relation))
4446  return;
4447 
4448  /* Check if someone else has already decided that we need to die */
4450  ereport(ERROR,
4452  errmsg("could not serialize access due to read/write dependencies among transactions"),
4453  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4454  errhint("The transaction might succeed if retried.")));
4455 
4456  /*
4457  * We're doing a write which might cause rw-conflicts now or later.
4458  * Memorize that fact.
4459  */
4460  MyXactDidWrite = true;
4461 
4462  /*
4463  * It is important that we check for locks from the finest granularity to
4464  * the coarsest granularity, so that granularity promotion doesn't cause
4465  * us to miss a lock. The new (coarser) lock will be acquired before the
4466  * old (finer) locks are released.
4467  *
4468  * It is not possible to take and hold a lock across the checks for all
4469  * granularities because each target could be in a separate partition.
4470  */
4471  if (tid != NULL)
4472  {
4474  relation->rd_locator.dbOid,
4475  relation->rd_id,
4478  CheckTargetForConflictsIn(&targettag);
4479  }
4480 
4481  if (blkno != InvalidBlockNumber)
4482  {
4484  relation->rd_locator.dbOid,
4485  relation->rd_id,
4486  blkno);
4487  CheckTargetForConflictsIn(&targettag);
4488  }
4489 
4491  relation->rd_locator.dbOid,
4492  relation->rd_id);
4493  CheckTargetForConflictsIn(&targettag);
4494 }
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1229
int errhint(const char *fmt,...)
Definition: elog.c:1316
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition: itemptr.h:124
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition: itemptr.h:103
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:75
static bool MyXactDidWrite
Definition: predicate.c:418
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:558
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4259
#define SxactIsDoomed(sxact)
Definition: predicate.c:276
#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:112
RelFileLocator rd_locator
Definition: rel.h:56

References CheckTargetForConflictsIn(), RelFileLocator::dbOid, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, InvalidBlockNumber, ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), MySerializableXact, MyXactDidWrite, RelationData::rd_id, RelationData::rd_locator, 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 4116 of file predicate.c.

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

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 4084 of file predicate.c.

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

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:339
static SerialControl serialControl
Definition: predicate.c:350
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1157
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1227
TransactionId tailXid
Definition: predicate.c:345

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 4524 of file predicate.c.

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

References Assert(), RelFileLocator::dbOid, 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, PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredXact, RelationData::rd_id, RelationData::rd_index, RelationData::rd_locator, 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 4259 of file predicate.c.

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

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, 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:395
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:358
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:292

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, 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:350
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
int max_predicate_locks_per_xact
Definition: predicate.c:367
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()

static SERIALIZABLEXACT * CreatePredXact ( void  )
static

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

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:229

References Assert(), DecrementParentLocks(), HASH_REMOVE, hash_search_with_hash_value(), IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, 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 LWLockHeldByMe(LWLock *lock)
Definition: lwlock.c:1918
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1962

References Assert(), HASH_REMOVE, hash_search_with_hash_value(), LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMe(), LWLockHeldByMeInMode(), LWLockRelease(), 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_locator.dbOid;
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:496
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, RelFileLocator::dbOid, 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, OldCommittedSxact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLockByIndex, PredicateLockingNeededForRelation(), SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredicateLockTargetTagHashCode, PREDLOCKTAG_RELATION, PredXact, RelationData::rd_id, RelationData::rd_index, RelationData::rd_locator, 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)
619  offsetof(PredXactListElementData, link));
620  if (!ptle)
621  return NULL;
622 
623  return &ptle->sxact;
624 }

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

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

◆ FlagRWConflict()

static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4616 of file predicate.c.

4617 {
4618  Assert(reader != writer);
4619 
4620  /* First, see if this conflict causes failure. */
4622 
4623  /* Actually do the conflict flagging. */
4624  if (reader == OldCommittedSxact)
4626  else if (writer == OldCommittedSxact)
4628  else
4629  SetRWConflict(reader, writer);
4630 }
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:686
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4651
#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:287
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, 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:1377
void * palloc(Size size)
Definition: mcxt.c:1199
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  origSnapshot)
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:1156
#define DEBUG2
Definition: elog.h:29
#define InvalidPid
Definition: miscadmin.h:32
#define SxactIsROUnsafe(sxact)
Definition: predicate.c:288
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:1878
@ 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:286
static SERIALIZABLEXACT * NextPredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:627

References FirstPredXact(), RWConflictData::inLink, LW_SHARED, LWLockAcquire(), LWLockRelease(), NextPredXact(), 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_transaction_isolation() if default_transaction_isolation is set
1689  * to 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:1202
static Snapshot GetSafeSnapshot(Snapshot origSnapshot)
Definition: predicate.c:1559
#define IsolationIsSerializable()
Definition: xact.h:52
bool RecoveryInProgress(void)
Definition: xlog.c:5912

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 }
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:2214
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition: procarray.c:2577
void SHMQueueElemInit(SHM_QUEUE *queue)
Definition: shmqueue.c:57
PGPROC * MyProc
Definition: proc.c:68
Definition: proc.h:162
int pgprocno
Definition: proc.h:191
SerCommitSeqNo LastSxactCommitSeqNo
VirtualTransactionId vxid
SerCommitSeqNo prepareSeqNo
TransactionId xmin
Definition: snapshot.h:157
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:307
#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:541
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:729
@ LWTRANCHE_PER_XACT_PREDICATE_LIST
Definition: lwlock.h:200
static LWLock * ScratchPartitionLock
Definition: predicate.c:404
static uint32 ScratchTargetTagHash
Definition: predicate.c:403
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:402
#define NPREDICATELOCKTARGETENTS()
Definition: predicate.c:260
static RWConflictPoolHeader RWConflictPool
Definition: predicate.c:386
#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:85
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:369
int max_predicate_locks_per_relation
Definition: predicate.c:368

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)
635  - offsetof(PredXactListElementData, sxact)
636  + offsetof(PredXactListElementData, link));
637  ptle = (PredXactListElement)
639  &ptle->link,
640  offsetof(PredXactListElementData, 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, 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 4651 of file predicate.c.

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

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, 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_locator.dbOid,
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 RelFileLocator::dbOid, HASH_FIND, hash_search_with_hash_value(), LW_SHARED, LWLockAcquire(), LWLockRelease(), PredicateLockHashPartitionLock, PredicateLockTargetHash, PredicateLockTargetTagHashCode, RelationData::rd_id, RelationData::rd_locator, and SET_PREDICATELOCKTARGETTAG_PAGE.

◆ PostPrepare_PredicateLocks()

void PostPrepare_PredicateLocks ( TransactionId  xid)

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4826 of file predicate.c.

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

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

497 {
498  return !(relation->rd_id < FirstUnpinnedObjectId ||
499  RelationUsesLocalBuffers(relation));
500 }
#define RelationUsesLocalBuffers(relation)
Definition: rel.h:635
#define FirstUnpinnedObjectId
Definition: transam.h:196

References FirstUnpinnedObjectId, RelationData::rd_id, 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_locator.dbOid,
3198  relation->rd_id,
3199  oldblkno);
3200  SET_PREDICATELOCKTARGETTAG_PAGE(newtargettag,
3201  relation->rd_locator.dbOid,
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 }
static bool BlockNumberIsValid(BlockNumber blockNumber)
Definition: block.h:71
static bool success
Definition: initdb.c:170
static bool TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag, PREDICATELOCKTARGETTAG newtargettag, bool removeOld)
Definition: predicate.c:2735

References Assert(), BlockNumberIsValid(), RelFileLocator::dbOid, GetParentPredicateLockTag(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PredicateLockingNeededForRelation(), PredXact, RelationData::rd_id, RelationData::rd_locator, 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_locator.dbOid,
2580  relation->rd_id);
2581  PredicateLockAcquire(&tag);
2582 }

References RelFileLocator::dbOid, PredicateLockAcquire(), RelationData::rd_id, RelationData::rd_locator, 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:781
#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_locator.dbOid,
2642  relation->rd_id);
2643  if (PredicateLockExists(&tag))
2644  return;
2645 
2647  relation->rd_locator.dbOid,
2648  relation->rd_id,
2651  PredicateLockAcquire(&tag);
2652 }
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:925

References RelFileLocator::dbOid, ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), PredicateLockAcquire(), PredicateLockExists(), RelationData::rd_id, RelationData::rd_index, RelationData::rd_locator, 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 5019 of file predicate.c.

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

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:263
#define SxactIsRolledBack(sxact)
Definition: predicate.c:275

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, 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:427
#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:1890
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, 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

Definition at line 597 of file predicate.c.

598 {
599  PredXactListElement ptle;
600 
601  Assert(ShmemAddrIsValid(sxact));
602 
603  ptle = (PredXactListElement)
604  (((char *) sxact)
605  - offsetof(PredXactListElementData, sxact)
606  + offsetof(PredXactListElementData, link));
607  SHMQueueDelete(&ptle->link);
609 }

References Assert(), PredXactListData::availableList, PredXactListElementData::link, PredXact, ShmemAddrIsValid(), SHMQueueDelete(), and SHMQueueInsertBefore().

Referenced by GetSerializableTransactionSnapshotInt(), and ReleaseOneSerializableXact().

◆ 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, 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:588
#define SerialNextPage(page)
Definition: predicate.c:333
#define SerialValue(slotno, xid)
Definition: predicate.c:335
static bool SerialPagePrecedesLogically(int page1, int page2)
Definition: predicate.c:791
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:281
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:396
TransactionId headXid
Definition: predicate.c:344

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 = SerialValue(slotno, xid);
1007  LWLockRelease(SerialSLRULock);
1008  return val;
1009 }
long val
Definition: informix.c:664
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:496

References Assert(), SerialControlData::headXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), serialControl, SerialPage, SerialSlruCtl, SerialValue, SimpleLruReadPage_ReadOnly(), SerialControlData::tailXid, TransactionIdFollows(), TransactionIdIsValid, TransactionIdPrecedes(), and val.

Referenced by CheckForSerializableConflictOut().

◆ SerialInit()

static void SerialInit ( void  )
static

Definition at line 866 of file predicate.c.

867 {
868  bool found;
869 
870  /*
871  * Set up SLRU management of the pg_serial data.
872  */
874  SimpleLruInit(SerialSlruCtl, "Serial",