PostgreSQL Source Code  git master
predicate.c File Reference
#include "postgres.h"
#include "access/parallel.h"
#include "access/slru.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/predicate.h"
#include "storage/predicate_internals.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/guc_hooks.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)   (!dlist_node_is_detached(&(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 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 (int64 page1, int64 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)
 
bool check_serial_buffers (int *newval, void **extra, GucSource source)
 
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 dlist_headFinishedSerializableTransactions
 
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 264 of file predicate.c.

◆ PredicateLockHashCodeFromTargetHashCode

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

Definition at line 316 of file predicate.c.

◆ PredicateLockHashPartition

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

Definition at line 256 of file predicate.c.

◆ PredicateLockHashPartitionLock

#define PredicateLockHashPartitionLock (   hashcode)
Value:
PredicateLockHashPartition(hashcode)].lock)
LWLockPadded * MainLWLockArray
Definition: lwlock.c:191
#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET
Definition: lwlock.h:107
LWLock lock
Definition: lwlock.h:70

Definition at line 258 of file predicate.c.

◆ PredicateLockHashPartitionLockByIndex

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

Definition at line 261 of file predicate.c.

◆ PredicateLockTargetTagHashCode

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

Definition at line 303 of file predicate.c.

◆ SERIAL_ENTRIESPERPAGE

#define SERIAL_ENTRIESPERPAGE   (SERIAL_PAGESIZE / SERIAL_ENTRYSIZE)

Definition at line 330 of file predicate.c.

◆ SERIAL_ENTRYSIZE

#define SERIAL_ENTRYSIZE   sizeof(SerCommitSeqNo)

Definition at line 329 of file predicate.c.

◆ SERIAL_MAX_PAGE

#define SERIAL_MAX_PAGE   (MaxTransactionId / SERIAL_ENTRIESPERPAGE)

Definition at line 335 of file predicate.c.

◆ SERIAL_PAGESIZE

#define SERIAL_PAGESIZE   BLCKSZ

Definition at line 328 of file predicate.c.

◆ SerialNextPage

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

Definition at line 337 of file predicate.c.

◆ SerialPage

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

Definition at line 343 of file predicate.c.

◆ SerialSlruCtl

#define SerialSlruCtl   (&SerialSlruCtlData)

Definition at line 326 of file predicate.c.

◆ SerialValue

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

Definition at line 339 of file predicate.c.

◆ SxactHasConflictOut

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

Definition at line 289 of file predicate.c.

◆ SxactHasSummaryConflictIn

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

Definition at line 282 of file predicate.c.

◆ SxactHasSummaryConflictOut

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

Definition at line 283 of file predicate.c.

◆ SxactIsCommitted

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

Definition at line 277 of file predicate.c.

◆ SxactIsDeferrableWaiting

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

Definition at line 290 of file predicate.c.

◆ SxactIsDoomed

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

Definition at line 280 of file predicate.c.

◆ SxactIsOnFinishedList

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

Definition at line 267 of file predicate.c.

◆ SxactIsPartiallyReleased

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

Definition at line 293 of file predicate.c.

◆ SxactIsPrepared

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

Definition at line 278 of file predicate.c.

◆ SxactIsReadOnly

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

Definition at line 281 of file predicate.c.

◆ SxactIsRolledBack

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

Definition at line 279 of file predicate.c.

◆ SxactIsROSafe

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

Definition at line 291 of file predicate.c.

◆ SxactIsROUnsafe

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

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

Typedef Documentation

◆ SerialControl

Definition at line 352 of file predicate.c.

◆ SerialControlData

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4775 of file predicate.c.

4776 {
4777  SERIALIZABLEXACT *sxact;
4778  TwoPhasePredicateRecord record;
4779  TwoPhasePredicateXactRecord *xactRecord;
4780  TwoPhasePredicateLockRecord *lockRecord;
4781  dlist_iter iter;
4782 
4783  sxact = MySerializableXact;
4784  xactRecord = &(record.data.xactRecord);
4785  lockRecord = &(record.data.lockRecord);
4786 
4788  return;
4789 
4790  /* Generate an xact record for our SERIALIZABLEXACT */
4792  xactRecord->xmin = MySerializableXact->xmin;
4793  xactRecord->flags = MySerializableXact->flags;
4794 
4795  /*
4796  * Note that we don't include the list of conflicts in our out in the
4797  * statefile, because new conflicts can be added even after the
4798  * transaction prepares. We'll just make a conservative assumption during
4799  * recovery instead.
4800  */
4801 
4803  &record, sizeof(record));
4804 
4805  /*
4806  * Generate a lock record for each lock.
4807  *
4808  * To do this, we need to walk the predicate lock list in our sxact rather
4809  * than using the local predicate lock table because the latter is not
4810  * guaranteed to be accurate.
4811  */
4812  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4813 
4814  /*
4815  * No need to take sxact->perXactPredicateListLock in parallel mode
4816  * because there cannot be any parallel workers running while we are
4817  * preparing a transaction.
4818  */
4820 
4821  dlist_foreach(iter, &sxact->predicateLocks)
4822  {
4823  PREDICATELOCK *predlock =
4824  dlist_container(PREDICATELOCK, xactLink, iter.cur);
4825 
4827  lockRecord->target = predlock->tag.myTarget->tag;
4828 
4830  &record, sizeof(record));
4831  }
4832 
4833  LWLockRelease(SerializablePredicateListLock);
4834 }
bool ParallelContextActive(void)
Definition: parallel.c:1003
#define Assert(condition)
Definition: c.h:858
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
#define IsParallelWorker()
Definition: parallel.h:60
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1170
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783
@ LW_SHARED
Definition: lwlock.h:115
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:421
@ TWOPHASEPREDICATERECORD_XACT
@ TWOPHASEPREDICATERECORD_LOCK
#define InvalidSerializableXact
PREDICATELOCKTARGET * myTarget
PREDICATELOCKTARGETTAG tag
PREDICATELOCKTAG tag
PREDICATELOCKTARGETTAG target
TwoPhasePredicateRecordType type
union TwoPhasePredicateRecord::@116 data
TwoPhasePredicateLockRecord lockRecord
TwoPhasePredicateXactRecord xactRecord
dlist_node * cur
Definition: ilist.h:179
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1280
#define TWOPHASE_RM_PREDICATELOCK_ID
Definition: twophase_rmgr.h:28

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

Referenced by PrepareTransaction().

◆ AttachSerializableXact()

void AttachSerializableXact ( SerializableXactHandle  handle)

Definition at line 5040 of file predicate.c.

5041 {
5042 
5044 
5045  MySerializableXact = (SERIALIZABLEXACT *) handle;
5048 }
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1925

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

Referenced by ParallelWorkerMain().

◆ check_serial_buffers()

bool check_serial_buffers ( int *  newval,
void **  extra,
GucSource  source 
)

Definition at line 847 of file predicate.c.

848 {
849  return check_slru_buffers("serializable_buffers", newval);
850 }
#define newval
bool check_slru_buffers(const char *name, int *newval)
Definition: slru.c:340

References check_slru_buffers(), and newval.

◆ CheckAndPromotePredicateLockRequest()

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2311 of file predicate.c.

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

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

4322 {
4323  PREDICATELOCKTARGETTAG targettag;
4324 
4325  if (!SerializationNeededForWrite(relation))
4326  return;
4327 
4328  /* Check if someone else has already decided that we need to die */
4330  ereport(ERROR,
4332  errmsg("could not serialize access due to read/write dependencies among transactions"),
4333  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4334  errhint("The transaction might succeed if retried.")));
4335 
4336  /*
4337  * We're doing a write which might cause rw-conflicts now or later.
4338  * Memorize that fact.
4339  */
4340  MyXactDidWrite = true;
4341 
4342  /*
4343  * It is important that we check for locks from the finest granularity to
4344  * the coarsest granularity, so that granularity promotion doesn't cause
4345  * us to miss a lock. The new (coarser) lock will be acquired before the
4346  * old (finer) locks are released.
4347  *
4348  * It is not possible to take and hold a lock across the checks for all
4349  * granularities because each target could be in a separate partition.
4350  */
4351  if (tid != NULL)
4352  {
4354  relation->rd_locator.dbOid,
4355  relation->rd_id,
4358  CheckTargetForConflictsIn(&targettag);
4359  }
4360 
4361  if (blkno != InvalidBlockNumber)
4362  {
4364  relation->rd_locator.dbOid,
4365  relation->rd_id,
4366  blkno);
4367  CheckTargetForConflictsIn(&targettag);
4368  }
4369 
4371  relation->rd_locator.dbOid,
4372  relation->rd_id);
4373  CheckTargetForConflictsIn(&targettag);
4374 }
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1230
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:857
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#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:76
static bool MyXactDidWrite
Definition: predicate.c:422
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:560
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4151
#define SxactIsDoomed(sxact)
Definition: predicate.c:280
#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:113
RelFileLocator rd_locator
Definition: rel.h:57

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

4009 {
4010  SERIALIZABLEXIDTAG sxidtag;
4011  SERIALIZABLEXID *sxid;
4012  SERIALIZABLEXACT *sxact;
4013 
4014  if (!SerializationNeededForRead(relation, snapshot))
4015  return;
4016 
4017  /* Check if someone else has already decided that we need to die */
4019  {
4020  ereport(ERROR,
4022  errmsg("could not serialize access due to read/write dependencies among transactions"),
4023  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4024  errhint("The transaction might succeed if retried.")));
4025  }
4027 
4029  return;
4030 
4031  /*
4032  * Find sxact or summarized info for the top level xid.
4033  */
4034  sxidtag.xid = xid;
4035  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4036  sxid = (SERIALIZABLEXID *)
4037  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4038  if (!sxid)
4039  {
4040  /*
4041  * Transaction not found in "normal" SSI structures. Check whether it
4042  * got pushed out to SLRU storage for "old committed" transactions.
4043  */
4044  SerCommitSeqNo conflictCommitSeqNo;
4045 
4046  conflictCommitSeqNo = SerialGetMinConflictCommitSeqNo(xid);
4047  if (conflictCommitSeqNo != 0)
4048  {
4049  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4051  || conflictCommitSeqNo
4053  ereport(ERROR,
4055  errmsg("could not serialize access due to read/write dependencies among transactions"),
4056  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4057  errhint("The transaction might succeed if retried.")));
4058 
4061  ereport(ERROR,
4063  errmsg("could not serialize access due to read/write dependencies among transactions"),
4064  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4065  errhint("The transaction might succeed if retried.")));
4066 
4068  }
4069 
4070  /* It's not serializable or otherwise not important. */
4071  LWLockRelease(SerializableXactHashLock);
4072  return;
4073  }
4074  sxact = sxid->myXact;
4075  Assert(TransactionIdEquals(sxact->topXid, xid));
4076  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4077  {
4078  /* Can't conflict with ourself or a transaction that will roll back. */
4079  LWLockRelease(SerializableXactHashLock);
4080  return;
4081  }
4082 
4083  /*
4084  * We have a conflict out to a transaction which has a conflict out to a
4085  * summarized transaction. That summarized transaction must have
4086  * committed first, and we can't tell when it committed in relation to our
4087  * snapshot acquisition, so something needs to be canceled.
4088  */
4089  if (SxactHasSummaryConflictOut(sxact))
4090  {
4091  if (!SxactIsPrepared(sxact))
4092  {
4093  sxact->flags |= SXACT_FLAG_DOOMED;
4094  LWLockRelease(SerializableXactHashLock);
4095  return;
4096  }
4097  else
4098  {
4099  LWLockRelease(SerializableXactHashLock);
4100  ereport(ERROR,
4102  errmsg("could not serialize access due to read/write dependencies among transactions"),
4103  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4104  errhint("The transaction might succeed if retried.")));
4105  }
4106  }
4107 
4108  /*
4109  * If this is a read-only transaction and the writing transaction has
4110  * committed, and it doesn't have a rw-conflict to a transaction which
4111  * committed before it, no conflict.
4112  */
4114  && SxactIsCommitted(sxact)
4115  && !SxactHasSummaryConflictOut(sxact)
4116  && (!SxactHasConflictOut(sxact)
4118  {
4119  /* Read-only transaction will appear to run first. No conflict. */
4120  LWLockRelease(SerializableXactHashLock);
4121  return;
4122  }
4123 
4124  if (!XidIsConcurrent(xid))
4125  {
4126  /* This write was already in our snapshot; no conflict. */
4127  LWLockRelease(SerializableXactHashLock);
4128  return;
4129  }
4130 
4132  {
4133  /* We don't want duplicate conflict records in the list. */
4134  LWLockRelease(SerializableXactHashLock);
4135  return;
4136  }
4137 
4138  /*
4139  * Flag the conflict. But first, if this conflict creates a dangerous
4140  * structure, ereport an error.
4141  */
4143  LWLockRelease(SerializableXactHashLock);
4144 }
@ HASH_FIND
Definition: hsearch.h:113
static bool dlist_is_empty(const dlist_head *head)
Definition: ilist.h:336
@ LW_EXCLUSIVE
Definition: lwlock.h:114
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:610
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:516
#define SxactIsCommitted(sxact)
Definition: predicate.c:277
#define SxactIsReadOnly(sxact)
Definition: predicate.c:281
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:282
#define SxactHasConflictOut(sxact)
Definition: predicate.c:289
#define SxactIsPrepared(sxact)
Definition: predicate.c:278
static HTAB * SerializableXidHash
Definition: predicate.c:396
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4486
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:944
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:3957
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:283
#define InvalidSerCommitSeqNo
#define SXACT_FLAG_DOOMED
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
union SERIALIZABLEXACT::@115 SeqNo
SerCommitSeqNo lastCommitBeforeSnapshot
SerCommitSeqNo earliestOutConflictCommit
SERIALIZABLEXACT * myXact
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:438

References Assert, dlist_is_empty(), 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(), 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 3976 of file predicate.c.

3977 {
3978  if (!SerializationNeededForRead(relation, snapshot))
3979  return false;
3980 
3981  /* Check if someone else has already decided that we need to die */
3983  {
3984  ereport(ERROR,
3986  errmsg("could not serialize access due to read/write dependencies among transactions"),
3987  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
3988  errhint("The transaction might succeed if retried.")));
3989  }
3990 
3991  return true;
3992 }

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

Referenced by heap_prepare_pagescan(), and HeapCheckForSerializableConflictOut().

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 1036 of file predicate.c.

1037 {
1038  int truncateCutoffPage;
1039 
1040  LWLockAcquire(SerialControlLock, LW_EXCLUSIVE);
1041 
1042  /* Exit quickly if the SLRU is currently not in use. */
1043  if (serialControl->headPage < 0)
1044  {
1045  LWLockRelease(SerialControlLock);
1046  return;
1047  }
1048 
1050  {
1051  int tailPage;
1052 
1053  tailPage = SerialPage(serialControl->tailXid);
1054 
1055  /*
1056  * It is possible for the tailXid to be ahead of the headXid. This
1057  * occurs if we checkpoint while there are in-progress serializable
1058  * transaction(s) advancing the tail but we are yet to summarize the
1059  * transactions. In this case, we cutoff up to the headPage and the
1060  * next summary will advance the headXid.
1061  */
1063  {
1064  /* We can truncate the SLRU up to the page containing tailXid */
1065  truncateCutoffPage = tailPage;
1066  }
1067  else
1068  truncateCutoffPage = serialControl->headPage;
1069  }
1070  else
1071  {
1072  /*----------
1073  * The SLRU is no longer needed. Truncate to head before we set head
1074  * invalid.
1075  *
1076  * XXX: It's possible that the SLRU is not needed again until XID
1077  * wrap-around has happened, so that the segment containing headPage
1078  * that we leave behind will appear to be new again. In that case it
1079  * won't be removed until XID horizon advances enough to make it
1080  * current again.
1081  *
1082  * XXX: This should happen in vac_truncate_clog(), not in checkpoints.
1083  * Consider this scenario, starting from a system with no in-progress
1084  * transactions and VACUUM FREEZE having maximized oldestXact:
1085  * - Start a SERIALIZABLE transaction.
1086  * - Start, finish, and summarize a SERIALIZABLE transaction, creating
1087  * one SLRU page.
1088  * - Consume XIDs to reach xidStopLimit.
1089  * - Finish all transactions. Due to the long-running SERIALIZABLE
1090  * transaction, earlier checkpoints did not touch headPage. The
1091  * next checkpoint will change it, but that checkpoint happens after
1092  * the end of the scenario.
1093  * - VACUUM to advance XID limits.
1094  * - Consume ~2M XIDs, crossing the former xidWrapLimit.
1095  * - Start, finish, and summarize a SERIALIZABLE transaction.
1096  * SerialAdd() declines to create the targetPage, because headPage
1097  * is not regarded as in the past relative to that targetPage. The
1098  * transaction instigating the summarize fails in
1099  * SimpleLruReadPage().
1100  */
1101  truncateCutoffPage = serialControl->headPage;
1102  serialControl->headPage = -1;
1103  }
1104 
1105  LWLockRelease(SerialControlLock);
1106 
1107  /*
1108  * Truncate away pages that are no longer required. Note that no
1109  * additional locking is required, because this is only called as part of
1110  * a checkpoint, and the validity limits have already been determined.
1111  */
1112  SimpleLruTruncate(SerialSlruCtl, truncateCutoffPage);
1113 
1114  /*
1115  * Write dirty SLRU pages to disk
1116  *
1117  * This is not actually necessary from a correctness point of view. We do
1118  * it merely as a debugging aid.
1119  *
1120  * We're doing this after the truncation to avoid writing pages right
1121  * before deleting the file in which they sit, which would be completely
1122  * pointless.
1123  */
1125 }
#define SerialPage(xid)
Definition: predicate.c:343
static SerialControl serialControl
Definition: predicate.c:354
static bool SerialPagePrecedesLogically(int64 page1, int64 page2)
Definition: predicate.c:731
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1304
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition: slru.c:1390
TransactionId tailXid
Definition: predicate.c:349

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

Referenced by CheckPointGuts().

◆ CheckTableForSerializableConflictIn()

void CheckTableForSerializableConflictIn ( Relation  relation)

Definition at line 4404 of file predicate.c.

4405 {
4406  HASH_SEQ_STATUS seqstat;
4407  PREDICATELOCKTARGET *target;
4408  Oid dbId;
4409  Oid heapId;
4410  int i;
4411 
4412  /*
4413  * Bail out quickly if there are no serializable transactions running.
4414  * It's safe to check this without taking locks because the caller is
4415  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4416  * would matter here can be acquired while that is held.
4417  */
4419  return;
4420 
4421  if (!SerializationNeededForWrite(relation))
4422  return;
4423 
4424  /*
4425  * We're doing a write which might cause rw-conflicts now or later.
4426  * Memorize that fact.
4427  */
4428  MyXactDidWrite = true;
4429 
4430  Assert(relation->rd_index == NULL); /* not an index relation */
4431 
4432  dbId = relation->rd_locator.dbOid;
4433  heapId = relation->rd_id;
4434 
4435  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
4436  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4438  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4439 
4440  /* Scan through target list */
4442 
4443  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4444  {
4445  dlist_mutable_iter iter;
4446 
4447  /*
4448  * Check whether this is a target which needs attention.
4449  */
4450  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4451  continue; /* wrong relation id */
4452  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4453  continue; /* wrong database id */
4454 
4455  /*
4456  * Loop through locks for this target and flag conflicts.
4457  */
4458  dlist_foreach_modify(iter, &target->predicateLocks)
4459  {
4460  PREDICATELOCK *predlock =
4461  dlist_container(PREDICATELOCK, targetLink, iter.cur);
4462 
4463  if (predlock->tag.myXact != MySerializableXact
4465  {
4467  }
4468  }
4469  }
4470 
4471  /* Release locks in reverse order */
4472  LWLockRelease(SerializableXactHashLock);
4473  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4475  LWLockRelease(SerializablePredicateListLock);
4476 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1395
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
#define dlist_foreach_modify(iter, lhead)
Definition: ilist.h:640
int i
Definition: isn.c:73
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:101
unsigned int Oid
Definition: postgres_ext.h:31
static PredXactList PredXact
Definition: predicate.c:384
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:261
static HTAB * PredicateLockTargetHash
Definition: predicate.c:397
SERIALIZABLEXACT * myXact
TransactionId SxactGlobalXmin
Form_pg_index rd_index
Definition: rel.h:192
dlist_node * cur
Definition: ilist.h:200

References Assert, dlist_mutable_iter::cur, RelFileLocator::dbOid, dlist_container, dlist_foreach_modify, 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(), PredXactListData::SxactGlobalXmin, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, and TransactionIdIsValid.

Referenced by ExecuteTruncateGuts(), and heap_drop_with_catalog().

◆ CheckTargetForConflictsIn()

static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag)
static

Definition at line 4151 of file predicate.c.

4152 {
4153  uint32 targettaghash;
4154  LWLock *partitionLock;
4155  PREDICATELOCKTARGET *target;
4156  PREDICATELOCK *mypredlock = NULL;
4157  PREDICATELOCKTAG mypredlocktag;
4158  dlist_mutable_iter iter;
4159 
4161 
4162  /*
4163  * The same hash and LW lock apply to the lock target and the lock itself.
4164  */
4165  targettaghash = PredicateLockTargetTagHashCode(targettag);
4166  partitionLock = PredicateLockHashPartitionLock(targettaghash);
4167  LWLockAcquire(partitionLock, LW_SHARED);
4168  target = (PREDICATELOCKTARGET *)
4170  targettag, targettaghash,
4171  HASH_FIND, NULL);
4172  if (!target)
4173  {
4174  /* Nothing has this target locked; we're done here. */
4175  LWLockRelease(partitionLock);
4176  return;
4177  }
4178 
4179  /*
4180  * Each lock for an overlapping transaction represents a conflict: a
4181  * rw-dependency in to this transaction.
4182  */
4183  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4184 
4185  dlist_foreach_modify(iter, &target->predicateLocks)
4186  {
4187  PREDICATELOCK *predlock =
4188  dlist_container(PREDICATELOCK, targetLink, iter.cur);
4189  SERIALIZABLEXACT *sxact = predlock->tag.myXact;
4190 
4191  if (sxact == MySerializableXact)
4192  {
4193  /*
4194  * If we're getting a write lock on a tuple, we don't need a
4195  * predicate (SIREAD) lock on the same tuple. We can safely remove
4196  * our SIREAD lock, but we'll defer doing so until after the loop
4197  * because that requires upgrading to an exclusive partition lock.
4198  *
4199  * We can't use this optimization within a subtransaction because
4200  * the subtransaction could roll back, and we would be left
4201  * without any lock at the top level.
4202  */
4203  if (!IsSubTransaction()
4204  && GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
4205  {
4206  mypredlock = predlock;
4207  mypredlocktag = predlock->tag;
4208  }
4209  }
4210  else if (!SxactIsDoomed(sxact)
4211  && (!SxactIsCommitted(sxact)
4213  sxact->finishedBefore))
4215  {
4216  LWLockRelease(SerializableXactHashLock);
4217  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4218 
4219  /*
4220  * Re-check after getting exclusive lock because the other
4221  * transaction may have flagged a conflict.
4222  */
4223  if (!SxactIsDoomed(sxact)
4224  && (!SxactIsCommitted(sxact)
4226  sxact->finishedBefore))
4228  {
4230  }
4231 
4232  LWLockRelease(SerializableXactHashLock);
4233  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4234  }
4235  }
4236  LWLockRelease(SerializableXactHashLock);
4237  LWLockRelease(partitionLock);
4238 
4239  /*
4240  * If we found one of our own SIREAD locks to remove, remove it now.
4241  *
4242  * At this point our transaction already has a RowExclusiveLock on the
4243  * relation, so we are OK to drop the predicate lock on the tuple, if
4244  * found, without fearing that another write against the tuple will occur
4245  * before the MVCC information makes it to the buffer.
4246  */
4247  if (mypredlock != NULL)
4248  {
4249  uint32 predlockhashcode;
4250  PREDICATELOCK *rmpredlock;
4251 
4252  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4253  if (IsInParallelMode())
4255  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4256  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4257 
4258  /*
4259  * Remove the predicate lock from shared memory, if it wasn't removed
4260  * while the locks were released. One way that could happen is from
4261  * autovacuum cleaning up an index.
4262  */
4263  predlockhashcode = PredicateLockHashCodeFromTargetHashCode
4264  (&mypredlocktag, targettaghash);
4265  rmpredlock = (PREDICATELOCK *)
4267  &mypredlocktag,
4268  predlockhashcode,
4269  HASH_FIND, NULL);
4270  if (rmpredlock != NULL)
4271  {
4272  Assert(rmpredlock == mypredlock);
4273 
4274  dlist_delete(&(mypredlock->targetLink));
4275  dlist_delete(&(mypredlock->xactLink));
4276 
4277  rmpredlock = (PREDICATELOCK *)
4279  &mypredlocktag,
4280  predlockhashcode,
4281  HASH_REMOVE, NULL);
4282  Assert(rmpredlock == mypredlock);
4283 
4284  RemoveTargetIfNoLongerUsed(target, targettaghash);
4285  }
4286 
4287  LWLockRelease(SerializableXactHashLock);
4288  LWLockRelease(partitionLock);
4289  if (IsInParallelMode())
4291  LWLockRelease(SerializablePredicateListLock);
4292 
4293  if (rmpredlock != NULL)
4294  {
4295  /*
4296  * Remove entry in local lock table if it exists. It's OK if it
4297  * doesn't exist; that means the lock was transferred to a new
4298  * target by a different backend.
4299  */
4301  targettag, targettaghash,
4302  HASH_REMOVE, NULL);
4303 
4304  DecrementParentLocks(targettag);
4305  }
4306  }
4307 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:968
@ HASH_REMOVE
Definition: hsearch.h:115
static void dlist_delete(dlist_node *node)
Definition: ilist.h:405
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2376
static HTAB * PredicateLockHash
Definition: predicate.c:398
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:303
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2168
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:316
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:258
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:216
Definition: lwlock.h:42
TransactionId finishedBefore
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
bool IsSubTransaction(void)
Definition: xact.c:4988
bool IsInParallelMode(void)
Definition: xact.c:1086

References Assert, dlist_mutable_iter::cur, DecrementParentLocks(), dlist_container, dlist_delete(), dlist_foreach_modify, 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(), SxactIsCommitted, SxactIsDoomed, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdPrecedes(), and PREDICATELOCK::xactLink.

Referenced by CheckForSerializableConflictIn().

◆ ClearOldPredicateLocks()

static void ClearOldPredicateLocks ( void  )
static

Definition at line 3682 of file predicate.c.

3683 {
3684  dlist_mutable_iter iter;
3685 
3686  /*
3687  * Loop through finished transactions. They are in commit order, so we can
3688  * stop as soon as we find one that's still interesting.
3689  */
3690  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3691  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3693  {
3694  SERIALIZABLEXACT *finishedSxact =
3695  dlist_container(SERIALIZABLEXACT, finishedLink, iter.cur);
3696 
3700  {
3701  /*
3702  * This transaction committed before any in-progress transaction
3703  * took its snapshot. It's no longer interesting.
3704  */
3705  LWLockRelease(SerializableXactHashLock);
3706  dlist_delete_thoroughly(&finishedSxact->finishedLink);
3707  ReleaseOneSerializableXact(finishedSxact, false, false);
3708  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3709  }
3710  else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3711  && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3712  {
3713  /*
3714  * Any active transactions that took their snapshot before this
3715  * transaction committed are read-only, so we can clear part of
3716  * its state.
3717  */
3718  LWLockRelease(SerializableXactHashLock);
3719 
3720  if (SxactIsReadOnly(finishedSxact))
3721  {
3722  /* A read-only transaction can be removed entirely */
3723  dlist_delete_thoroughly(&(finishedSxact->finishedLink));
3724  ReleaseOneSerializableXact(finishedSxact, false, false);
3725  }
3726  else
3727  {
3728  /*
3729  * A read-write transaction can only be partially cleared. We
3730  * need to keep the SERIALIZABLEXACT but can release the
3731  * SIREAD locks and conflicts in.
3732  */
3733  ReleaseOneSerializableXact(finishedSxact, true, false);
3734  }
3735 
3737  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3738  }
3739  else
3740  {
3741  /* Still interesting. */
3742  break;
3743  }
3744  }
3745  LWLockRelease(SerializableXactHashLock);
3746 
3747  /*
3748  * Loop through predicate locks on dummy transaction for summarized data.
3749  */
3750  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
3752  {
3753  PREDICATELOCK *predlock =
3754  dlist_container(PREDICATELOCK, xactLink, iter.cur);
3755  bool canDoPartialCleanup;
3756 
3757  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3758  Assert(predlock->commitSeqNo != 0);
3760  canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
3761  LWLockRelease(SerializableXactHashLock);
3762 
3763  /*
3764  * If this lock originally belonged to an old enough transaction, we
3765  * can release it.
3766  */
3767  if (canDoPartialCleanup)
3768  {
3769  PREDICATELOCKTAG tag;
3770  PREDICATELOCKTARGET *target;
3771  PREDICATELOCKTARGETTAG targettag;
3772  uint32 targettaghash;
3773  LWLock *partitionLock;
3774 
3775  tag = predlock->tag;
3776  target = tag.myTarget;
3777  targettag = target->tag;
3778  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3779  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3780 
3781  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3782 
3783  dlist_delete(&(predlock->targetLink));
3784  dlist_delete(&(predlock->xactLink));
3785 
3788  targettaghash),
3789  HASH_REMOVE, NULL);
3790  RemoveTargetIfNoLongerUsed(target, targettaghash);
3791 
3792  LWLockRelease(partitionLock);
3793  }
3794  }
3795 
3796  LWLockRelease(SerializablePredicateListLock);
3797  LWLockRelease(SerializableFinishedListLock);
3798 }
static void dlist_delete_thoroughly(dlist_node *node)
Definition: ilist.h:416
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:362
static dlist_head * FinishedSerializableTransactions
Definition: predicate.c:399
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize)
Definition: predicate.c:3820
SerCommitSeqNo commitSeqNo
SerCommitSeqNo CanPartialClearThrough
SerCommitSeqNo HavePartialClearedThrough
SerCommitSeqNo commitSeqNo
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:299

References Assert, PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, PREDICATELOCK::commitSeqNo, dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_delete_thoroughly(), dlist_foreach_modify, 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(), 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 2096 of file predicate.c.

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

References GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

◆ CreateLocalPredicateLockHash()

static void CreateLocalPredicateLockHash ( void  )
static

Definition at line 1925 of file predicate.c.

1926 {
1927  HASHCTL hash_ctl;
1928 
1929  /* Initialize the backend-local hash table of parent locks */
1930  Assert(LocalPredicateLockHash == NULL);
1931  hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1932  hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1933  LocalPredicateLockHash = hash_create("Local predicate lock",
1935  &hash_ctl,
1936  HASH_ELEM | HASH_BLOBS);
1937 }
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
int max_predicate_locks_per_xact
Definition: predicate.c:371
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 2438 of file predicate.c.

2441 {
2442  PREDICATELOCKTARGET *target;
2443  PREDICATELOCKTAG locktag;
2444  PREDICATELOCK *lock;
2445  LWLock *partitionLock;
2446  bool found;
2447 
2448  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2449 
2450  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2451  if (IsInParallelMode())
2453  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2454 
2455  /* Make sure that the target is represented. */
2456  target = (PREDICATELOCKTARGET *)
2458  targettag, targettaghash,
2459  HASH_ENTER_NULL, &found);
2460  if (!target)
2461  ereport(ERROR,
2462  (errcode(ERRCODE_OUT_OF_MEMORY),
2463  errmsg("out of shared memory"),
2464  errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
2465  if (!found)
2466  dlist_init(&target->predicateLocks);
2467 
2468  /* We've got the sxact and target, make sure they're joined. */
2469  locktag.myTarget = target;
2470  locktag.myXact = sxact;
2471  lock = (PREDICATELOCK *)
2473  PredicateLockHashCodeFromTargetHashCode(&locktag, targettaghash),
2474  HASH_ENTER_NULL, &found);
2475  if (!lock)
2476  ereport(ERROR,
2477  (errcode(ERRCODE_OUT_OF_MEMORY),
2478  errmsg("out of shared memory"),
2479  errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
2480 
2481  if (!found)
2482  {
2483  dlist_push_tail(&target->predicateLocks, &lock->targetLink);
2484  dlist_push_tail(&sxact->predicateLocks, &lock->xactLink);
2486  }
2487 
2488  LWLockRelease(partitionLock);
2489  if (IsInParallelMode())
2491  LWLockRelease(SerializablePredicateListLock);
2492 }
@ HASH_ENTER_NULL
Definition: hsearch.h:116
static void dlist_init(dlist_head *head)
Definition: ilist.h:314
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364

References PREDICATELOCK::commitSeqNo, dlist_init(), dlist_push_tail(), 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, PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by predicatelock_twophase_recover(), and PredicateLockAcquire().

◆ CreatePredXact()

static SERIALIZABLEXACT * CreatePredXact ( void  )
static

Definition at line 582 of file predicate.c.

583 {
584  SERIALIZABLEXACT *sxact;
585 
587  return NULL;
588 
589  sxact = dlist_container(SERIALIZABLEXACT, xactLink,
592  return sxact;
593 }
static dlist_node * dlist_pop_head_node(dlist_head *head)
Definition: ilist.h:450

References PredXactListData::activeList, PredXactListData::availableList, dlist_container, dlist_is_empty(), dlist_pop_head_node(), dlist_push_tail(), PredXact, and SERIALIZABLEXACT::xactLink.

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

◆ DecrementParentLocks()

static void DecrementParentLocks ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2376 of file predicate.c.

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

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

2200 {
2201  SERIALIZABLEXACT *sxact;
2202  PREDICATELOCK *predlock;
2203  dlist_mutable_iter iter;
2204 
2205  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2206  sxact = MySerializableXact;
2207  if (IsInParallelMode())
2209 
2210  dlist_foreach_modify(iter, &sxact->predicateLocks)
2211  {
2212  PREDICATELOCKTAG oldlocktag;
2213  PREDICATELOCKTARGET *oldtarget;
2214  PREDICATELOCKTARGETTAG oldtargettag;
2215 
2216  predlock = dlist_container(PREDICATELOCK, xactLink, iter.cur);
2217 
2218  oldlocktag = predlock->tag;
2219  Assert(oldlocktag.myXact == sxact);
2220  oldtarget = oldlocktag.myTarget;
2221  oldtargettag = oldtarget->tag;
2222 
2223  if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
2224  {
2225  uint32 oldtargettaghash;
2226  LWLock *partitionLock;
2228 
2229  oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2230  partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2231 
2232  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2233 
2234  dlist_delete(&predlock->xactLink);
2235  dlist_delete(&predlock->targetLink);
2236  rmpredlock = hash_search_with_hash_value
2238  &oldlocktag,
2240  oldtargettaghash),
2241  HASH_REMOVE, NULL);
2242  Assert(rmpredlock == predlock);
2243 
2244  RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2245 
2246  LWLockRelease(partitionLock);
2247 
2248  DecrementParentLocks(&oldtargettag);
2249  }
2250  }
2251  if (IsInParallelMode())
2253  LWLockRelease(SerializablePredicateListLock);
2254 }
#define TargetTagIsCoveredBy(covered_target, covering_target)
Definition: predicate.c:233

References Assert, dlist_mutable_iter::cur, DecrementParentLocks(), dlist_container, dlist_delete(), dlist_foreach_modify, 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(), 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 2654 of file predicate.c.

2655 {
2656  dlist_mutable_iter iter;
2657 
2658  Assert(LWLockHeldByMeInMode(SerializablePredicateListLock,
2659  LW_EXCLUSIVE));
2661 
2662  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2663 
2664  dlist_foreach_modify(iter, &target->predicateLocks)
2665  {
2666  PREDICATELOCK *predlock =
2667  dlist_container(PREDICATELOCK, targetLink, iter.cur);
2668  bool found;
2669 
2670  dlist_delete(&(predlock->xactLink));
2671  dlist_delete(&(predlock->targetLink));
2672 
2675  &predlock->tag,
2677  targettaghash),
2678  HASH_REMOVE, &found);
2679  Assert(found);
2680  }
2681  LWLockRelease(SerializableXactHashLock);
2682 
2683  /* Remove the target itself, if possible. */
2684  RemoveTargetIfNoLongerUsed(target, targettaghash);
2685 }
bool LWLockHeldByMe(LWLock *lock)
Definition: lwlock.c:1895
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1939

References Assert, dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_foreach_modify, HASH_REMOVE, hash_search_with_hash_value(), LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMe(), LWLockHeldByMeInMode(), LWLockRelease(), PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PREDICATELOCKTARGET::predicateLocks, RemoveTargetIfNoLongerUsed(), PREDICATELOCK::tag, PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by TransferPredicateLocksToNewTarget().

◆ DropAllPredicateLocksFromTable()

static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
)
static

Definition at line 2922 of file predicate.c.

2923 {
2924  HASH_SEQ_STATUS seqstat;
2925  PREDICATELOCKTARGET *oldtarget;
2926  PREDICATELOCKTARGET *heaptarget;
2927  Oid dbId;
2928  Oid relId;
2929  Oid heapId;
2930  int i;
2931  bool isIndex;
2932  bool found;
2933  uint32 heaptargettaghash;
2934 
2935  /*
2936  * Bail out quickly if there are no serializable transactions running.
2937  * It's safe to check this without taking locks because the caller is
2938  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
2939  * would matter here can be acquired while that is held.
2940  */
2942  return;
2943 
2944  if (!PredicateLockingNeededForRelation(relation))
2945  return;
2946 
2947  dbId = relation->rd_locator.dbOid;
2948  relId = relation->rd_id;
2949  if (relation->rd_index == NULL)
2950  {
2951  isIndex = false;
2952  heapId = relId;
2953  }
2954  else
2955  {
2956  isIndex = true;
2957  heapId = relation->rd_index->indrelid;
2958  }
2959  Assert(heapId != InvalidOid);
2960  Assert(transfer || !isIndex); /* index OID only makes sense with
2961  * transfer */
2962 
2963  /* Retrieve first time needed, then keep. */
2964  heaptargettaghash = 0;
2965  heaptarget = NULL;
2966 
2967  /* Acquire locks on all lock partitions */
2968  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
2969  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
2971  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2972 
2973  /*
2974  * Remove the dummy entry to give us scratch space, so we know we'll be
2975  * able to create the new lock target.
2976  */
2977  if (transfer)
2978  RemoveScratchTarget(true);
2979 
2980  /* Scan through target map */
2982 
2983  while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
2984  {
2985  dlist_mutable_iter iter;
2986 
2987  /*
2988  * Check whether this is a target which needs attention.
2989  */
2990  if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) != relId)
2991  continue; /* wrong relation id */
2992  if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
2993  continue; /* wrong database id */
2994  if (transfer && !isIndex
2996  continue; /* already the right lock */
2997 
2998  /*
2999  * If we made it here, we have work to do. We make sure the heap
3000  * relation lock exists, then we walk the list of predicate locks for
3001  * the old target we found, moving all locks to the heap relation lock
3002  * -- unless they already hold that.
3003  */
3004 
3005  /*
3006  * First make sure we have the heap relation target. We only need to
3007  * do this once.
3008  */
3009  if (transfer && heaptarget == NULL)
3010  {
3011  PREDICATELOCKTARGETTAG heaptargettag;
3012 
3013  SET_PREDICATELOCKTARGETTAG_RELATION(heaptargettag, dbId, heapId);
3014  heaptargettaghash = PredicateLockTargetTagHashCode(&heaptargettag);
3016  &heaptargettag,
3017  heaptargettaghash,
3018  HASH_ENTER, &found);
3019  if (!found)
3020  dlist_init(&heaptarget->predicateLocks);
3021  }
3022 
3023  /*
3024  * Loop through all the locks on the old target, replacing them with
3025  * locks on the new target.
3026  */
3027  dlist_foreach_modify(iter, &oldtarget->predicateLocks)
3028  {
3029  PREDICATELOCK *oldpredlock =
3030  dlist_container(PREDICATELOCK, targetLink, iter.cur);
3031  PREDICATELOCK *newpredlock;
3032  SerCommitSeqNo oldCommitSeqNo;
3033  SERIALIZABLEXACT *oldXact;
3034 
3035  /*
3036  * Remove the old lock first. This avoids the chance of running
3037  * out of lock structure entries for the hash table.
3038  */
3039  oldCommitSeqNo = oldpredlock->commitSeqNo;
3040  oldXact = oldpredlock->tag.myXact;
3041 
3042  dlist_delete(&(oldpredlock->xactLink));
3043 
3044  /*
3045  * No need for retail delete from oldtarget list, we're removing
3046  * the whole target anyway.
3047  */
3049  &oldpredlock->tag,
3050  HASH_REMOVE, &found);
3051  Assert(found);
3052 
3053  if (transfer)
3054  {
3055  PREDICATELOCKTAG newpredlocktag;
3056 
3057  newpredlocktag.myTarget = heaptarget;
3058  newpredlocktag.myXact = oldXact;
3059  newpredlock = (PREDICATELOCK *)
3061  &newpredlocktag,
3063  heaptargettaghash),
3064  HASH_ENTER,
3065  &found);
3066  if (!found)
3067  {
3068  dlist_push_tail(&(heaptarget->predicateLocks),
3069  &(newpredlock->targetLink));
3070  dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
3071  &(newpredlock->xactLink));
3072  newpredlock->commitSeqNo = oldCommitSeqNo;
3073  }
3074  else
3075  {
3076  if (newpredlock->commitSeqNo < oldCommitSeqNo)
3077  newpredlock->commitSeqNo = oldCommitSeqNo;
3078  }
3079 
3080  Assert(newpredlock->commitSeqNo != 0);
3081  Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
3082  || (newpredlock->tag.myXact == OldCommittedSxact));
3083  }
3084  }
3085 
3087  &found);
3088  Assert(found);
3089  }
3090 
3091  /* Put the scratch entry back */
3092  if (transfer)
3093  RestoreScratchTarget(true);
3094 
3095  /* Release locks in reverse order */
3096  LWLockRelease(SerializableXactHashLock);
3097  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3099  LWLockRelease(SerializablePredicateListLock);
3100 }
#define InvalidOid
Definition: postgres_ext.h:36
static bool PredicateLockingNeededForRelation(Relation relation)
Definition: predicate.c:498
static void RestoreScratchTarget(bool lockheld)
Definition: predicate.c:2146
static void RemoveScratchTarget(bool lockheld)
Definition: predicate.c:2125
@ PREDLOCKTAG_RELATION
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)

References Assert, PREDICATELOCK::commitSeqNo, dlist_mutable_iter::cur, RelFileLocator::dbOid, dlist_container, dlist_delete(), dlist_foreach_modify, dlist_init(), dlist_push_tail(), 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, PredXactListData::SxactGlobalXmin, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdIsValid, and PREDICATELOCK::xactLink.

Referenced by TransferPredicateLocksToHeapRelation().

◆ FlagRWConflict()

static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4486 of file predicate.c.

4487 {
4488  Assert(reader != writer);
4489 
4490  /* First, see if this conflict causes failure. */
4492 
4493  /* Actually do the conflict flagging. */
4494  if (reader == OldCommittedSxact)
4496  else if (writer == OldCommittedSxact)
4498  else
4499  SetRWConflict(reader, writer);
4500 }
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:643
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4521
#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 699 of file predicate.c.

700 {
701  dlist_mutable_iter iter;
702 
703  Assert(SxactIsReadOnly(sxact));
704  Assert(!SxactIsROSafe(sxact));
705 
706  sxact->flags |= SXACT_FLAG_RO_UNSAFE;
707 
708  /*
709  * We know this isn't a safe snapshot, so we can stop looking for other
710  * potential conflicts.
711  */
713  {
714  RWConflict conflict =
715  dlist_container(RWConflictData, inLink, iter.cur);
716 
717  Assert(!SxactIsReadOnly(conflict->sxactOut));
718  Assert(sxact == conflict->sxactIn);
719 
720  ReleaseRWConflict(conflict);
721  }
722 }
#define SxactIsROSafe(sxact)
Definition: predicate.c:291
static void ReleaseRWConflict(RWConflict conflict)
Definition: predicate.c:691
#define SXACT_FLAG_RO_UNSAFE
SERIALIZABLEXACT * sxactIn
SERIALIZABLEXACT * sxactOut
dlist_head possibleUnsafeConflicts

References Assert, dlist_mutable_iter::cur, dlist_container, dlist_foreach_modify, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::possibleUnsafeConflicts, ReleaseRWConflict(), 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 2057 of file predicate.c.

2059 {
2060  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2061  {
2062  case PREDLOCKTAG_RELATION:
2063  /* relation locks have no parent lock */
2064  return false;
2065 
2066  case PREDLOCKTAG_PAGE:
2067  /* parent lock is relation lock */
2071 
2072  return true;
2073 
2074  case PREDLOCKTAG_TUPLE:
2075  /* parent lock is page lock */
2080  return true;
2081  }
2082 
2083  /* not reachable */
2084  Assert(false);
2085  return false;
2086 }
@ 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 1430 of file predicate.c.

1431 {
1433  int i;
1434  int els,
1435  el;
1436  HASH_SEQ_STATUS seqstat;
1437  PREDICATELOCK *predlock;
1438 
1440 
1441  /*
1442  * To ensure consistency, take simultaneous locks on all partition locks
1443  * in ascending order, then SerializableXactHashLock.
1444  */
1445  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
1447  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1448 
1449  /* Get number of locks and allocate appropriately-sized arrays. */
1451  data->nelements = els;
1452  data->locktags = (PREDICATELOCKTARGETTAG *)
1453  palloc(sizeof(PREDICATELOCKTARGETTAG) * els);
1454  data->xacts = (SERIALIZABLEXACT *)
1455  palloc(sizeof(SERIALIZABLEXACT) * els);
1456 
1457 
1458  /* Scan through PredicateLockHash and copy contents */
1459  hash_seq_init(&seqstat, PredicateLockHash);
1460 
1461  el = 0;
1462 
1463  while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
1464  {
1465  data->locktags[el] = predlock->tag.myTarget->tag;
1466  data->xacts[el] = *predlock->tag.myXact;
1467  el++;
1468  }
1469 
1470  Assert(el == els);
1471 
1472  /* Release locks in reverse order */
1473  LWLockRelease(SerializableXactHashLock);
1474  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1476 
1477  return data;
1478 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1341
void * palloc(Size size)
Definition: mcxt.c:1316
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 1543 of file predicate.c.

1544 {
1545  Snapshot snapshot;
1546 
1548 
1549  while (true)
1550  {
1551  /*
1552  * GetSerializableTransactionSnapshotInt is going to call
1553  * GetSnapshotData, so we need to provide it the static snapshot area
1554  * our caller passed to us. The pointer returned is actually the same
1555  * one passed to it, but we avoid assuming that here.
1556  */
1557  snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
1558  NULL, InvalidPid);
1559 
1561  return snapshot; /* no concurrent r/w xacts; it's safe */
1562 
1563  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1564 
1565  /*
1566  * Wait for concurrent transactions to finish. Stop early if one of
1567  * them marked us as conflicted.
1568  */
1572  {
1573  LWLockRelease(SerializableXactHashLock);
1574  ProcWaitForSignal(WAIT_EVENT_SAFE_SNAPSHOT);
1575  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1576  }
1578 
1580  {
1581  LWLockRelease(SerializableXactHashLock);
1582  break; /* success */
1583  }
1584 
1585  LWLockRelease(SerializableXactHashLock);
1586 
1587  /* else, need to retry... */
1588  ereport(DEBUG2,
1590  errmsg_internal("deferrable snapshot was unsafe; trying a new one")));
1591  ReleasePredicateLocks(false, false);
1592  }
1593 
1594  /*
1595  * Now we have a safe snapshot, so we don't need to do any further checks.
1596  */
1598  ReleasePredicateLocks(false, true);
1599 
1600  return snapshot;
1601 }
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
#define DEBUG2
Definition: elog.h:29
#define InvalidPid
Definition: miscadmin.h:32
#define SxactIsROUnsafe(sxact)
Definition: predicate.c:292
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1749
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3297
#define SXACT_FLAG_DEFERRABLE_WAITING
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1866
bool XactDeferrable
Definition: xact.c:83
bool XactReadOnly
Definition: xact.c:80

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

Referenced by GetSerializableTransactionSnapshot().

◆ GetSafeSnapshotBlockingPids()

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

Definition at line 1613 of file predicate.c.

1614 {
1615  int num_written = 0;
1616  dlist_iter iter;
1617  SERIALIZABLEXACT *blocking_sxact = NULL;
1618 
1619  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1620 
1621  /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
1623  {
1624  SERIALIZABLEXACT *sxact =
1625  dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
1626 
1627  if (sxact->pid == blocked_pid)
1628  {
1629  blocking_sxact = sxact;
1630  break;
1631  }
1632  }
1633 
1634  /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
1635  if (blocking_sxact != NULL && SxactIsDeferrableWaiting(blocking_sxact))
1636  {
1637  /* Traverse the list of possible unsafe conflicts collecting PIDs. */
1638  dlist_foreach(iter, &blocking_sxact->possibleUnsafeConflicts)
1639  {
1640  RWConflict possibleUnsafeConflict =
1641  dlist_container(RWConflictData, inLink, iter.cur);
1642 
1643  output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
1644 
1645  if (num_written >= output_size)
1646  break;
1647  }
1648  }
1649 
1650  LWLockRelease(SerializableXactHashLock);
1651 
1652  return num_written;
1653 }
FILE * output
#define SxactIsDeferrableWaiting(sxact)
Definition: predicate.c:290

References PredXactListData::activeList, dlist_iter::cur, dlist_container, dlist_foreach, LW_SHARED, LWLockAcquire(), LWLockRelease(), output, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, PredXact, 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 1667 of file predicate.c.

1668 {
1670 
1671  /*
1672  * Can't use serializable mode while recovery is still active, as it is,
1673  * for example, on a hot standby. We could get here despite the check in
1674  * check_transaction_isolation() if default_transaction_isolation is set
1675  * to serializable, so phrase the hint accordingly.
1676  */
1677  if (RecoveryInProgress())
1678  ereport(ERROR,
1679  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1680  errmsg("cannot use serializable mode in a hot standby"),
1681  errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1682  errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1683 
1684  /*
1685  * A special optimization is available for SERIALIZABLE READ ONLY
1686  * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1687  * thereby avoid all SSI overhead once it's running.
1688  */
1690  return GetSafeSnapshot(snapshot);
1691 
1692  return GetSerializableTransactionSnapshotInt(snapshot,
1693  NULL, InvalidPid);
1694 }
int errdetail(const char *fmt,...)
Definition: elog.c:1203
static Snapshot GetSafeSnapshot(Snapshot origSnapshot)
Definition: predicate.c:1543
#define IsolationIsSerializable()
Definition: xact.h:52
bool RecoveryInProgress(void)
Definition: xlog.c:6290

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

1752 {
1753  PGPROC *proc;
1754  VirtualTransactionId vxid;
1755  SERIALIZABLEXACT *sxact,
1756  *othersxact;
1757 
1758  /* We only do this for serializable transactions. Once. */
1760 
1762 
1763  /*
1764  * Since all parts of a serializable transaction must use the same
1765  * snapshot, it is too late to establish one after a parallel operation
1766  * has begun.
1767  */
1768  if (IsInParallelMode())
1769  elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
1770 
1771  proc = MyProc;
1772  Assert(proc != NULL);
1773  GET_VXID_FROM_PGPROC(vxid, *proc);
1774 
1775  /*
1776  * First we get the sxact structure, which may involve looping and access
1777  * to the "finished" list to free a structure for use.
1778  *
1779  * We must hold SerializableXactHashLock when taking/checking the snapshot
1780  * to avoid race conditions, for much the same reasons that
1781  * GetSnapshotData takes the ProcArrayLock. Since we might have to
1782  * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
1783  * this means we have to create the sxact first, which is a bit annoying
1784  * (in particular, an elog(ERROR) in procarray.c would cause us to leak
1785  * the sxact). Consider refactoring to avoid this.
1786  */
1787 #ifdef TEST_SUMMARIZE_SERIAL
1789 #endif
1790  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1791  do
1792  {
1793  sxact = CreatePredXact();
1794  /* If null, push out committed sxact to SLRU summary & retry. */
1795  if (!sxact)
1796  {
1797  LWLockRelease(SerializableXactHashLock);
1799  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1800  }
1801  } while (!sxact);
1802 
1803  /* Get the snapshot, or check that it's safe to use */
1804  if (!sourcevxid)
1805  snapshot = GetSnapshotData(snapshot);
1806  else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid))
1807  {
1808  ReleasePredXact(sxact);
1809  LWLockRelease(SerializableXactHashLock);
1810  ereport(ERROR,
1811  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1812  errmsg("could not import the requested snapshot"),
1813  errdetail("The source process with PID %d is not running anymore.",
1814  sourcepid)));
1815  }
1816 
1817  /*
1818  * If there are no serializable transactions which are not read-only, we
1819  * can "opt out" of predicate locking and conflict checking for a
1820  * read-only transaction.
1821  *
1822  * The reason this is safe is that a read-only transaction can only become
1823  * part of a dangerous structure if it overlaps a writable transaction
1824  * which in turn overlaps a writable transaction which committed before
1825  * the read-only transaction started. A new writable transaction can
1826  * overlap this one, but it can't meet the other condition of overlapping
1827  * a transaction which committed before this one started.
1828  */
1830  {
1831  ReleasePredXact(sxact);
1832  LWLockRelease(SerializableXactHashLock);
1833  return snapshot;
1834  }
1835 
1836  /* Initialize the structure. */
1837  sxact->vxid = vxid;
1841  dlist_init(&(sxact->outConflicts));
1842  dlist_init(&(sxact->inConflicts));
1844  sxact->topXid = GetTopTransactionIdIfAny();
1846  sxact->xmin = snapshot->xmin;
1847  sxact->pid = MyProcPid;
1848  sxact->pgprocno = MyProcNumber;
1849  dlist_init(&sxact->predicateLocks);
1850  dlist_node_init(&sxact->finishedLink);
1851  sxact->flags = 0;
1852  if (XactReadOnly)
1853  {
1854  dlist_iter iter;
1855 
1856  sxact->flags |= SXACT_FLAG_READ_ONLY;
1857 
1858  /*
1859  * Register all concurrent r/w transactions as possible conflicts; if
1860  * all of them commit without any outgoing conflicts to earlier
1861  * transactions then this snapshot can be deemed safe (and we can run
1862  * without tracking predicate locks).
1863  */
1865  {
1866  othersxact = dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
1867 
1868  if (!SxactIsCommitted(othersxact)
1869  && !SxactIsDoomed(othersxact)
1870  && !SxactIsReadOnly(othersxact))
1871  {
1872  SetPossibleUnsafeConflict(sxact, othersxact);
1873  }
1874  }
1875 
1876  /*
1877  * If we didn't find any possibly unsafe conflicts because every
1878  * uncommitted writable transaction turned out to be doomed, then we
1879  * can "opt out" immediately. See comments above the earlier check
1880  * for PredXact->WritableSxactCount == 0.
1881  */
1883  {
1884  ReleasePredXact(sxact);
1885  LWLockRelease(SerializableXactHashLock);
1886  return snapshot;
1887  }
1888  }
1889  else
1890  {
1894  }
1895 
1896  /* Maintain serializable global xmin info. */
1898  {
1900  PredXact->SxactGlobalXmin = snapshot->xmin;
1902  SerialSetActiveSerXmin(snapshot->xmin);
1903  }
1904  else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
1905  {
1908  }
1909  else
1910  {
1912  }
1913 
1914  MySerializableXact = sxact;
1915  MyXactDidWrite = false; /* haven't written anything yet */
1916 
1917  LWLockRelease(SerializableXactHashLock);
1918 
1920 
1921  return snapshot;
1922 }
#define elog(elevel,...)
Definition: elog.h:224
int MyProcPid
Definition: globals.c:45
ProcNumber MyProcNumber
Definition: globals.c:87
int MaxBackends
Definition: globals.c:143
static void dlist_node_init(dlist_node *node)
Definition: ilist.h:325
#define GET_VXID_FROM_PGPROC(vxid_dst, proc)
Definition: lock.h:77
static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
Definition: predicate.c:666
static void ReleasePredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:596
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:582
static void SerialSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:985
static void SummarizeOldestCommittedSxact(void)
Definition: predicate.c:1488
#define SXACT_FLAG_READ_ONLY
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:2165
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition: procarray.c:2524
PGPROC * MyProc
Definition: proc.c:66
Definition: proc.h:157
SerCommitSeqNo LastSxactCommitSeqNo
VirtualTransactionId vxid
SerCommitSeqNo prepareSeqNo
TransactionId xmin
Definition: snapshot.h:157
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:314
#define InvalidTransactionId
Definition: transam.h:31
int max_prepared_xacts
Definition: twophase.c:115

References PredXactListData::activeList, Assert, SERIALIZABLEXACT::commitSeqNo, CreateLocalPredicateLockHash(), CreatePredXact(), dlist_iter::cur, dlist_container, dlist_foreach, dlist_init(), dlist_is_empty(), dlist_node_init(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, 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, MyProcNumber, MyProcPid, MySerializableXact, MyXactDidWrite, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::predicateLocks, PredXact, SERIALIZABLEXACT::prepareSeqNo, ProcArrayInstallImportedXmin(), RecoveryInProgress(), ReleasePredXact(), SERIALIZABLEXACT::SeqNo, SerialSetActiveSerXmin(), SetPossibleUnsafeConflict(), 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 1140 of file predicate.c.

1141 {
1142  HASHCTL info;
1143  long max_table_size;
1144  Size requestSize;
1145  bool found;
1146 
1147 #ifndef EXEC_BACKEND
1149 #endif
1150 
1151  /*
1152  * Compute size of predicate lock target hashtable. Note these
1153  * calculations must agree with PredicateLockShmemSize!
1154  */
1155  max_table_size = NPREDICATELOCKTARGETENTS();
1156 
1157  /*
1158  * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1159  * per-predicate-lock-target information.
1160  */
1161  info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1162  info.entrysize = sizeof(PREDICATELOCKTARGET);
1164 
1165  PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1166  max_table_size,
1167  max_table_size,
1168  &info,
1169  HASH_ELEM | HASH_BLOBS |
1171 
1172  /*
1173  * Reserve a dummy entry in the hash table; we use it to make sure there's
1174  * always one entry available when we need to split or combine a page,
1175  * because running out of space there could mean aborting a
1176  * non-serializable transaction.
1177  */
1178  if (!IsUnderPostmaster)
1179  {
1181  HASH_ENTER, &found);
1182  Assert(!found);
1183  }
1184 
1185  /* Pre-calculate the hash and partition lock of the scratch entry */
1188 
1189  /*
1190  * Allocate hash table for PREDICATELOCK structs. This stores per
1191  * xact-lock-of-a-target information.
1192  */
1193  info.keysize = sizeof(PREDICATELOCKTAG);
1194  info.entrysize = sizeof(PREDICATELOCK);
1195  info.hash = predicatelock_hash;
1197 
1198  /* Assume an average of 2 xacts per target */
1199  max_table_size *= 2;
1200 
1201  PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1202  max_table_size,
1203  max_table_size,
1204  &info,
1207 
1208  /*
1209  * Compute size for serializable transaction hashtable. Note these
1210  * calculations must agree with PredicateLockShmemSize!
1211  */
1212  max_table_size = (MaxBackends + max_prepared_xacts);
1213 
1214  /*
1215  * Allocate a list to hold information on transactions participating in
1216  * predicate locking.
1217  *
1218  * Assume an average of 10 predicate locking transactions per backend.
1219  * This allows aggressive cleanup while detail is present before data must
1220  * be summarized for storage in SLRU and the "dummy" transaction.
1221  */
1222  max_table_size *= 10;
1223 
1224  PredXact = ShmemInitStruct("PredXactList",
1226  &found);
1227  Assert(found == IsUnderPostmaster);
1228  if (!found)
1229  {
1230  int i;
1231 
1240  requestSize = mul_size((Size) max_table_size,
1241  sizeof(SERIALIZABLEXACT));
1242  PredXact->element = ShmemAlloc(requestSize);
1243  /* Add all elements to available list, clean. */
1244  memset(PredXact->element, 0, requestSize);
1245  for (i = 0; i < max_table_size; i++)
1246  {
1250  }
1267  }
1268  /* This never changes, so let's keep a local copy. */
1270 
1271  /*
1272  * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1273  * information for serializable transactions which have accessed data.
1274  */
1275  info.keysize = sizeof(SERIALIZABLEXIDTAG);
1276  info.entrysize = sizeof(SERIALIZABLEXID);
1277 
1278  SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1279  max_table_size,
1280  max_table_size,
1281  &info,
1282  HASH_ELEM | HASH_BLOBS |
1283  HASH_FIXED_SIZE);
1284 
1285  /*
1286  * Allocate space for tracking rw-conflicts in lists attached to the
1287  * transactions.
1288  *
1289  * Assume an average of 5 conflicts per transaction. Calculations suggest
1290  * that this will prevent resource exhaustion in even the most pessimal
1291  * loads up to max_connections = 200 with all 200 connections pounding the
1292  * database with serializable transactions. Beyond that, there may be
1293  * occasional transactions canceled when trying to flag conflicts. That's
1294  * probably OK.
1295  */
1296  max_table_size *= 5;
1297 
1298  RWConflictPool = ShmemInitStruct("RWConflictPool",
1300  &found);
1301  Assert(found == IsUnderPostmaster);
1302  if (!found)
1303  {
1304  int i;
1305 
1307  requestSize = mul_size((Size) max_table_size,
1309  RWConflictPool->element = ShmemAlloc(requestSize);
1310  /* Add all elements to available list, clean. */
1311  memset(RWConflictPool->element, 0, requestSize);
1312  for (i = 0; i < max_table_size; i++)
1313  {
1316  }
1317  }
1318 
1319  /*
1320  * Create or attach to the header for the list of finished serializable
1321  * transactions.
1322  */
1324  ShmemInitStruct("FinishedSerializableTransactions",
1325  sizeof(dlist_head),
1326  &found);
1327  Assert(found == IsUnderPostmaster);
1328  if (!found)
1330 
1331  /*
1332  * Initialize the SLRU storage for old committed serializable
1333  * transactions.
1334  */
1335  SerialInit();
1336 }
size_t Size
Definition: c.h:605
bool IsUnderPostmaster
Definition: globals.c:117
#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:74
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:709
@ LWTRANCHE_PER_XACT_PREDICATE_LIST
Definition: lwlock.h:202
static LWLock * ScratchPartitionLock
Definition: predicate.c:408
static uint32 ScratchTargetTagHash
Definition: predicate.c:407
static uint32 predicatelock_hash(const void *key, Size keysize)
Definition: predicate.c:1404
static void SerialInit(void)
Definition: predicate.c:806
static const PREDICATELOCKTARGETTAG ScratchTargetTag
Definition: predicate.c:406
#define NPREDICATELOCKTARGETENTS()
Definition: predicate.c:264
static RWConflictPoolHeader RWConflictPool
Definition: predicate.c:390
#define RWConflictDataSize
#define FirstNormalSerCommitSeqNo
struct PREDICATELOCKTAG PREDICATELOCKTAG
#define PredXactListDataSize
#define RWConflictPoolHeaderDataSize
struct SERIALIZABLEXIDTAG SERIALIZABLEXIDTAG
struct PREDICATELOCKTARGET PREDICATELOCKTARGET
struct SERIALIZABLEXID SERIALIZABLEXID
#define SXACT_FLAG_COMMITTED
struct PREDICATELOCK PREDICATELOCK
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
void * ShmemAlloc(Size size)
Definition: shmem.c:152
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:332
HashValueFunc hash
Definition: hsearch.h:78
long num_partitions
Definition: hsearch.h:68
SERIALIZABLEXACT * element
SERIALIZABLEXACT * OldCommittedSxact

References PredXactListData::activeList, Assert, PredXactListData::availableList, RWConflictPoolHeaderData::availableList, PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, CreatePredXact(), dlist_init(), dlist_node_init(), dlist_push_tail(), 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_PROC_NUMBER, InvalidTransactionId, IsUnderPostmaster, HASHCTL::keysize, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, 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, SERIALIZABLEXACT::prepareSeqNo, RWConflictDataSize, RWConflictPool, RWConflictPoolHeaderDataSize, ScratchPartitionLock, ScratchTargetTag, ScratchTargetTagHash, SERIALIZABLEXACT::SeqNo, SerialInit(), SerializableXidHash, SetInvalidVirtualTransactionId, ShmemAlloc(), ShmemInitHash(), ShmemInitStruct(), SXACT_FLAG_COMMITTED, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SERIALIZABLEXACT::topXid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, SERIALIZABLEXACT::xactLink, and SERIALIZABLEXACT::xmin.

Referenced by CreateOrAttachShmemStructs().

◆ MaxPredicateChildLocks()

static int MaxPredicateChildLocks ( const PREDICATELOCKTARGETTAG tag)
static

Definition at line 2274 of file predicate.c.

2275 {
2276  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2277  {
2278  case PREDLOCKTAG_RELATION:
2283 
2284  case PREDLOCKTAG_PAGE:
2286 
2287  case PREDLOCKTAG_TUPLE:
2288 
2289  /*
2290  * not reachable: nothing is finer-granularity than a tuple, so we
2291  * should never try to promote to it.
2292  */
2293  Assert(false);
2294  return 0;
2295  }
2296 
2297  /* not reachable */
2298  Assert(false);
2299  return 0;
2300 }
int max_predicate_locks_per_page
Definition: predicate.c:373
int max_predicate_locks_per_relation
Definition: predicate.c:372

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

◆ OnConflict_CheckForSerializationFailure()

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

Definition at line 4521 of file predicate.c.

4523 {
4524  bool failure;
4525 
4526  Assert(LWLockHeldByMe(SerializableXactHashLock));
4527 
4528  failure = false;
4529 
4530  /*------------------------------------------------------------------------
4531  * Check for already-committed writer with rw-conflict out flagged
4532  * (conflict-flag on W means that T2 committed before W):
4533  *
4534  * R ------> W ------> T2
4535  * rw rw
4536  *
4537  * That is a dangerous structure, so we must abort. (Since the writer
4538  * has already committed, we must be the reader)
4539  *------------------------------------------------------------------------
4540  */
4541  if (SxactIsCommitted(writer)
4542  && (SxactHasConflictOut(writer) || SxactHasSummaryConflictOut(writer)))
4543  failure = true;
4544 
4545  /*------------------------------------------------------------------------
4546  * Check whether the writer has become a pivot with an out-conflict
4547  * committed transaction (T2), and T2 committed first:
4548  *
4549  * R ------> W ------> T2
4550  * rw rw
4551  *
4552  * Because T2 must've committed first, there is no anomaly if:
4553  * - the reader committed before T2
4554  * - the writer committed before T2
4555  * - the reader is a READ ONLY transaction and the reader was concurrent
4556  * with T2 (= reader acquired its snapshot before T2 committed)
4557  *
4558  * We also handle the case that T2 is prepared but not yet committed
4559  * here. In that case T2 has already checked for conflicts, so if it
4560  * commits first, making the above conflict real, it's too late for it
4561  * to abort.
4562  *------------------------------------------------------------------------
4563  */
4564  if (!failure && SxactHasSummaryConflictOut(writer))
4565  failure = true;
4566  else if (!failure)
4567  {
4568  dlist_iter iter;
4569 
4570  dlist_foreach(iter, &writer->outConflicts)
4571  {
4572  RWConflict conflict =
4573  dlist_container(RWConflictData, outLink, iter.cur);
4574  SERIALIZABLEXACT *t2 = conflict->sxactIn;
4575 
4576  if (SxactIsPrepared(t2)
4577  && (!SxactIsCommitted(reader)
4578  || t2->prepareSeqNo <= reader->commitSeqNo)
4579  && (!SxactIsCommitted(writer)
4580  || t2->prepareSeqNo <= writer->commitSeqNo)
4581  && (!SxactIsReadOnly(reader)
4582  || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
4583  {
4584  failure = true;
4585  break;
4586  }
4587  }
4588  }
4589 
4590  /*------------------------------------------------------------------------
4591  * Check whether the reader has become a pivot with a writer
4592  * that's committed (or prepared):
4593  *
4594  * T0 ------> R ------> W
4595  * rw rw
4596  *
4597  * Because W must've committed first for an anomaly to occur, there is no
4598  * anomaly if:
4599  * - T0 committed before the writer
4600  * - T0 is READ ONLY, and overlaps the writer
4601  *------------------------------------------------------------------------
4602  */
4603  if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
4604  {
4605  if (SxactHasSummaryConflictIn(reader))
4606  {
4607  failure = true;
4608  }
4609  else
4610  {
4611  dlist_iter iter;
4612 
4613  /*
4614  * The unconstify is needed as we have no const version of
4615  * dlist_foreach().
4616  */
4617  dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->inConflicts)
4618  {
4619  const RWConflict conflict =
4620  dlist_container(RWConflictData, inLink, iter.cur);
4621  const SERIALIZABLEXACT *t0 = conflict->sxactOut;
4622 
4623  if (!SxactIsDoomed(t0)
4624  && (!SxactIsCommitted(t0)
4625  || t0->commitSeqNo >= writer->prepareSeqNo)
4626  && (!SxactIsReadOnly(t0)
4627  || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
4628  {
4629  failure = true;
4630  break;
4631  }
4632  }
4633  }
4634  }
4635 
4636  if (failure)
4637  {
4638  /*
4639  * We have to kill a transaction to avoid a possible anomaly from
4640  * occurring. If the writer is us, we can just ereport() to cause a
4641  * transaction abort. Otherwise we flag the writer for termination,
4642  * causing it to abort when it tries to commit. However, if the writer
4643  * is a prepared transaction, already prepared, we can't abort it
4644  * anymore, so we have to kill the reader instead.
4645  */
4646  if (MySerializableXact == writer)
4647  {
4648  LWLockRelease(SerializableXactHashLock);
4649  ereport(ERROR,
4651  errmsg("could not serialize access due to read/write dependencies among transactions"),
4652  errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
4653  errhint("The transaction might succeed if retried.")));
4654  }
4655  else if (SxactIsPrepared(writer))
4656  {
4657  LWLockRelease(SerializableXactHashLock);
4658 
4659  /* if we're not the writer, we have to be the reader */
4660  Assert(MySerializableXact == reader);
4661  ereport(ERROR,
4663  errmsg("could not serialize access due to read/write dependencies among transactions"),
4664  errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
4665  errhint("The transaction might succeed if retried.")));
4666  }
4667  writer->flags |= SXACT_FLAG_DOOMED;
4668  }
4669 }
#define unconstify(underlying_type, expr)
Definition: c.h:1245

References Assert, SERIALIZABLEXACT::commitSeqNo, dlist_iter::cur, dlist_container, dlist_foreach, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LWLockHeldByMe(), LWLockRelease(), MySerializableXact, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::prepareSeqNo, SERIALIZABLEXACT::SeqNo, SXACT_FLAG_DOOMED, SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, RWConflictData::sxactIn, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, RWConflictData::sxactOut, SERIALIZABLEXACT::topXid, and unconstify.

Referenced by FlagRWConflict().

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

Definition at line 1993 of file predicate.c.

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

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

4689 {
4690  dlist_iter near_iter;
4691 
4693  return;
4694 
4696 
4697  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4698 
4699  /*
4700  * Check if someone else has already decided that we need to die. Since
4701  * we set our own DOOMED flag when partially releasing, ignore in that
4702  * case.
4703  */
4706  {
4707  LWLockRelease(SerializableXactHashLock);
4708  ereport(ERROR,
4710  errmsg("could not serialize access due to read/write dependencies among transactions"),
4711  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4712  errhint("The transaction might succeed if retried.")));
4713  }
4714 
4716  {
4717  RWConflict nearConflict =
4718  dlist_container(RWConflictData, inLink, near_iter.cur);
4719 
4720  if (!SxactIsCommitted(nearConflict->sxactOut)
4721  && !SxactIsDoomed(nearConflict->sxactOut))
4722  {
4723  dlist_iter far_iter;
4724 
4725  dlist_foreach(far_iter, &nearConflict->sxactOut->inConflicts)
4726  {
4727  RWConflict farConflict =
4728  dlist_container(RWConflictData, inLink, far_iter.cur);
4729 
4730  if (farConflict->sxactOut == MySerializableXact
4731  || (!SxactIsCommitted(farConflict->sxactOut)
4732  && !SxactIsReadOnly(farConflict->sxactOut)
4733  && !SxactIsDoomed(farConflict->sxactOut)))
4734  {
4735  /*
4736  * Normally, we kill the pivot transaction to make sure we
4737  * make progress if the failing transaction is retried.
4738  * However, we can't kill it if it's already prepared, so
4739  * in that case we commit suicide instead.
4740  */
4741  if (SxactIsPrepared(nearConflict->sxactOut))
4742  {
4743  LWLockRelease(SerializableXactHashLock);
4744  ereport(ERROR,
4746  errmsg("could not serialize access due to read/write dependencies among transactions"),
4747  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4748  errhint("The transaction might succeed if retried.")));
4749  }
4750  nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4751  break;
4752  }
4753  }
4754  }
4755  }
4756 
4759 
4760  LWLockRelease(SerializableXactHashLock);
4761 }
#define SxactIsPartiallyReleased(sxact)
Definition: predicate.c:293
#define SXACT_FLAG_PREPARED

References Assert, dlist_iter::cur, dlist_container, dlist_foreach, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::inConflicts, InvalidSerializableXact, IsolationIsSerializable, PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, PredXact, SERIALIZABLEXACT::prepareSeqNo, 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 1404 of file predicate.c.

1405 {
1406  const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
1407  uint32 targethash;
1408 
1409  Assert(keysize == sizeof(PREDICATELOCKTAG));
1410 
1411  /* Look into the associated target object, and compute its hash code */
1412  targethash = PredicateLockTargetTagHashCode(&predicatelocktag->myTarget->tag);
1413 
1414  return PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash);
1415 }

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

4896 {
4897  TwoPhasePredicateRecord *record;
4898 
4899  Assert(len == sizeof(TwoPhasePredicateRecord));
4900 
4901  record = (TwoPhasePredicateRecord *) recdata;
4902 
4903  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
4904  (record->type == TWOPHASEPREDICATERECORD_LOCK));
4905 
4906  if (record->type == TWOPHASEPREDICATERECORD_XACT)
4907  {
4908  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4909  TwoPhasePredicateXactRecord *xactRecord;
4910  SERIALIZABLEXACT *sxact;
4911  SERIALIZABLEXID *sxid;
4912  SERIALIZABLEXIDTAG sxidtag;
4913  bool found;
4914 
4915  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4916 
4917  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4918  sxact = CreatePredXact();
4919  if (!sxact)
4920  ereport(ERROR,
4921  (errcode(ERRCODE_OUT_OF_MEMORY),
4922  errmsg("out of shared memory")));
4923 
4924  /* vxid for a prepared xact is INVALID_PROC_NUMBER/xid; no pid */
4927  sxact->pid = 0;
4928  sxact->pgprocno = INVALID_PROC_NUMBER;
4929 
4930  /* a prepared xact hasn't committed yet */
4934 
4936 
4937  /*
4938  * Don't need to track this; no transactions running at the time the
4939  * recovered xact started are still active, except possibly other
4940  * prepared xacts and we don't care whether those are RO_SAFE or not.
4941  */
4943 
4944  dlist_init(&(sxact->predicateLocks));
4945  dlist_node_init(&sxact->finishedLink);
4946 
4947  sxact->topXid = xid;
4948  sxact->xmin = xactRecord->xmin;
4949  sxact->flags = xactRecord->flags;
4950  Assert(SxactIsPrepared(sxact));
4951  if (!SxactIsReadOnly(sxact))
4952  {
4956  }
4957 
4958  /*
4959  * We don't know whether the transaction had any conflicts or not, so
4960  * we'll conservatively assume that it had both a conflict in and a
4961  * conflict out, and represent that with the summary conflict flags.
4962  */
4963  dlist_init(&(sxact->outConflicts));
4964  dlist_init(&(sxact->inConflicts));
4967 
4968  /* Register the transaction's xid */
4969  sxidtag.xid = xid;
4971  &sxidtag,
4972  HASH_ENTER, &found);
4973  Assert(sxid != NULL);
4974  Assert(!found);
4975  sxid->myXact = (SERIALIZABLEXACT *) sxact;
4976 
4977  /*
4978  * Update global xmin. Note that this is a special case compared to
4979  * registering a normal transaction, because the global xmin might go
4980  * backwards. That's OK, because until recovery is over we're not
4981  * going to complete any transactions or create any non-prepared
4982  * transactions, so there's no danger of throwing away.
4983  */
4986  {
4987  PredXact->SxactGlobalXmin = sxact->xmin;
4989  SerialSetActiveSerXmin(sxact->xmin);
4990  }
4991  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
4992  {
4995  }
4996 
4997  LWLockRelease(SerializableXactHashLock);
4998  }
4999  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
5000  {
5001  /* Lock record. Recreate the PREDICATELOCK */
5002  TwoPhasePredicateLockRecord *lockRecord;
5003  SERIALIZABLEXID *sxid;
5004  SERIALIZABLEXACT *sxact;
5005  SERIALIZABLEXIDTAG sxidtag;
5006  uint32 targettaghash;
5007 
5008  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
5009  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
5010 
5011  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
5012  sxidtag.xid = xid;
5013  sxid = (SERIALIZABLEXID *)
5014  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
5015  LWLockRelease(SerializableXactHashLock);
5016 
5017  Assert(sxid != NULL);
5018  sxact = sxid->myXact;
5019  Assert(sxact != InvalidSerializableXact);
5020 
5021  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5022  }
5023 }
uint32 LocalTransactionId
Definition: c.h:654
const void size_t len
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2438
#define RecoverySerCommitSeqNo
LocalTransactionId localTransactionId
Definition: lock.h:62
ProcNumber procNumber
Definition: lock.h:61

References Assert, SERIALIZABLEXACT::commitSeqNo, CreatePredicateLock(), CreatePredXact(), TwoPhasePredicateRecord::data, dlist_init(), dlist_node_init(), ereport, errcode(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, SERIALIZABLEXACT::flags, TwoPhasePredicateXactRecord::flags, HASH_ENTER, HASH_FIND, hash_search(), SERIALIZABLEXACT::inConflicts, INVALID_PROC_NUMBER, 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, VirtualTransactionId::procNumber, RecoverySerCommitSeqNo, SERIALIZABLEXACT::SeqNo, SerializableXidHash, SerialSetActiveSerXmin(), 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 2502 of file predicate.c.

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

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

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

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

499 {
500  return !(relation->rd_id < FirstUnpinnedObjectId ||
501  RelationUsesLocalBuffers(relation));
502 }
#define RelationUsesLocalBuffers(relation)
Definition: rel.h:637
#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 3214 of file predicate.c.

3216 {
3217  /*
3218  * Page combines differ from page splits in that we ought to be able to
3219  * remove the locks on the old page after transferring them to the new
3220  * page, instead of duplicating them. However, because we can't edit other
3221  * backends' local lock tables, removing the old lock would leave them
3222  * with an entry in their LocalPredicateLockHash for a lock they're not
3223  * holding, which isn't acceptable. So we wind up having to do the same
3224  * work as a page split, acquiring a lock on the new page and keeping the
3225  * old page locked too. That can lead to some false positives, but should
3226  * be rare in practice.
3227  */
3228  PredicateLockPageSplit(relation, oldblkno, newblkno);
3229 }
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3129

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

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

Definition at line 3129 of file predicate.c.

3131 {
3132  PREDICATELOCKTARGETTAG oldtargettag;
3133  PREDICATELOCKTARGETTAG newtargettag;
3134  bool success;
3135 
3136  /*
3137  * Bail out quickly if there are no serializable transactions running.
3138  *
3139  * It's safe to do this check without taking any additional locks. Even if
3140  * a serializable transaction starts concurrently, we know it can't take
3141  * any SIREAD locks on the page being split because the caller is holding
3142  * the associated buffer page lock. Memory reordering isn't an issue; the
3143  * memory barrier in the LWLock acquisition guarantees that this read
3144  * occurs while the buffer page lock is held.
3145  */
3147  return;
3148 
3149  if (!PredicateLockingNeededForRelation(relation))
3150  return;
3151 
3152  Assert(oldblkno != newblkno);
3153  Assert(BlockNumberIsValid(oldblkno));
3154  Assert(BlockNumberIsValid(newblkno));
3155 
3156  SET_PREDICATELOCKTARGETTAG_PAGE(oldtargettag,
3157  relation->rd_locator.dbOid,
3158  relation->rd_id,
3159  oldblkno);
3160  SET_PREDICATELOCKTARGETTAG_PAGE(newtargettag,
3161  relation->rd_locator.dbOid,
3162  relation->rd_id,
3163  newblkno);
3164 
3165  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
3166 
3167  /*
3168  * Try copying the locks over to the new page's tag, creating it if
3169  * necessary.
3170  */
3172  newtargettag,
3173  false);
3174 
3175  if (!success)
3176  {
3177  /*
3178  * No more predicate lock entries are available. Failure isn't an
3179  * option here, so promote the page lock to a relation lock.
3180  */
3181 
3182  /* Get the parent relation lock's lock tag */
3183  success = GetParentPredicateLockTag(&oldtargettag,
3184  &newtargettag);
3185  Assert(success);
3186 
3187  /*
3188  * Move the locks to the parent. This shouldn't fail.
3189  *
3190  * Note that here we are removing locks held by other backends,
3191  * leading to a possible inconsistency in their local lock hash table.
3192  * This is OK because we're replacing it with a lock that covers the
3193  * old one.
3194  */
3196  newtargettag,
3197  true);
3198  Assert(success);
3199  }
3200 
3201  LWLockRelease(SerializablePredicateListLock);
3202 }
static bool BlockNumberIsValid(BlockNumber blockNumber)
Definition: block.h:71
static bool success
Definition: initdb.c:186
static bool TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag, PREDICATELOCKTARGETTAG newtargettag, bool removeOld)
Definition: predicate.c:2715

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

2562 {
2564 
2565  if (!SerializationNeededForRead(relation, snapshot))
2566  return;
2567 
2569  relation->rd_locator.dbOid,
2570  relation->rd_id);
2571  PredicateLockAcquire(&tag);
2572 }

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

1343 {
1344  Size size = 0;
1345  long max_table_size;
1346 
1347  /* predicate lock target hash table */
1348  max_table_size = NPREDICATELOCKTARGETENTS();
1349  size = add_size(size, hash_estimate_size(max_table_size,
1350  sizeof(PREDICATELOCKTARGET)));
1351 
1352  /* predicate lock hash table */
1353  max_table_size *= 2;
1354  size = add_size(size, hash_estimate_size(max_table_size,
1355  sizeof(PREDICATELOCK)));
1356 
1357  /*
1358  * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
1359  * margin.
1360  */
1361  size = add_size(size, size / 10);
1362 
1363  /* transaction list */
1364  max_table_size = MaxBackends + max_prepared_xacts;
1365  max_table_size *= 10;
1367  size = add_size(size, mul_size((Size) max_table_size,
1368  sizeof(SERIALIZABLEXACT)));
1369 
1370  /* transaction xid table */
1371  size = add_size(size, hash_estimate_size(max_table_size,
1372  sizeof(SERIALIZABLEXID)));
1373 
1374  /* rw-conflict pool */
1375  max_table_size *= 5;
1377  size = add_size(size, mul_size((Size) max_table_size,
1379 
1380  /* Head for list of finished serializable transactions. */
1381  size = add_size(size, sizeof(dlist_head));
1382 
1383  /* Shared memory structures for SLRU tracking of old committed xids. */
1384  size = add_size(size, sizeof(SerialControlData));
1386 
1387  return size;
1388 }
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:783
int serializable_buffers
Definition: globals.c:166
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
static pg_noinline void Size size
Definition: slab.c:607
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:184

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

Referenced by CalculateShmemSize().

◆ PredicateLockTID()

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

Definition at line 2606 of file predicate.c.

2608 {
2610 
2611  if (!SerializationNeededForRead(relation, snapshot))
2612  return;
2613 
2614  /*
2615  * Return if this xact wrote it.
2616  */
2617  if (relation->rd_index == NULL)
2618  {
2619  /* If we wrote it; we already have a write lock. */
2620  if (TransactionIdIsCurrentTransactionId(tuple_xid))
2621  return;
2622  }
2623 
2624  /*
2625  * Do quick-but-not-definitive test for a relation lock first. This will
2626  * never cause a return when the relation is *not* locked, but will
2627  * occasionally let the check continue when there really *is* a relation
2628  * level lock.
2629  */
2631  relation->rd_locator.dbOid,
2632  relation->rd_id);
2633  if (PredicateLockExists(&tag))
2634  return;
2635 
2637  relation->rd_locator.dbOid,
2638  relation->rd_id,
2641  PredicateLockAcquire(&tag);
2642 }
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:938

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

4868 {
4869  SERIALIZABLEXID *sxid;
4870  SERIALIZABLEXIDTAG sxidtag;
4871 
4872  sxidtag.xid = xid;
4873 
4874  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4875  sxid = (SERIALIZABLEXID *)
4876  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4877  LWLockRelease(SerializableXactHashLock);
4878 
4879  /* xid will not be found if it wasn't a serializable transaction */
4880  if (sxid == NULL)
4881  return;
4882 
4883  /* Release its locks */
4884  MySerializableXact = sxid->myXact;
4885  MyXactDidWrite = true; /* conservatively assume that we wrote
4886  * something */
4887  ReleasePredicateLocks(isCommit, false);
4888 }

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

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

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

3822 {
3823  SERIALIZABLEXIDTAG sxidtag;
3824  dlist_mutable_iter iter;
3825 
3826  Assert(sxact != NULL);
3827  Assert(SxactIsRolledBack(sxact) || SxactIsCommitted(sxact));
3828  Assert(partial || !SxactIsOnFinishedList(sxact));
3829  Assert(LWLockHeldByMe(SerializableFinishedListLock));
3830 
3831  /*
3832  * First release all the predicate locks held by this xact (or transfer
3833  * them to OldCommittedSxact if summarize is true)
3834  */
3835  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
3836  if (IsInParallelMode())
3838  dlist_foreach_modify(iter, &sxact->predicateLocks)
3839  {
3840  PREDICATELOCK *predlock =
3841  dlist_container(PREDICATELOCK, xactLink, iter.cur);
3842  PREDICATELOCKTAG tag;
3843  PREDICATELOCKTARGET *target;
3844  PREDICATELOCKTARGETTAG targettag;
3845  uint32 targettaghash;
3846  LWLock *partitionLock;
3847 
3848  tag = predlock->tag;
3849  target = tag.myTarget;
3850  targettag = target->tag;
3851  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3852  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3853 
3854  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3855 
3856  dlist_delete(&predlock->targetLink);
3857 
3860  targettaghash),
3861  HASH_REMOVE, NULL);
3862  if (summarize)
3863  {
3864  bool found;
3865 
3866  /* Fold into dummy transaction list. */
3867  tag.myXact = OldCommittedSxact;
3870  targettaghash),
3871  HASH_ENTER_NULL, &found);
3872  if (!predlock)
3873  ereport(ERROR,
3874  (errcode(ERRCODE_OUT_OF_MEMORY),
3875  errmsg("out of shared memory"),
3876  errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
3877  if (found)
3878  {
3879  Assert(predlock->commitSeqNo != 0);
3881  if (predlock->commitSeqNo < sxact->commitSeqNo)
3882  predlock->commitSeqNo = sxact->commitSeqNo;
3883  }
3884  else
3885  {
3887  &predlock->targetLink);
3889  &predlock->xactLink);
3890  predlock->commitSeqNo = sxact->commitSeqNo;
3891  }
3892  }
3893  else
3894  RemoveTargetIfNoLongerUsed(target, targettaghash);
3895 
3896  LWLockRelease(partitionLock);
3897  }
3898 
3899  /*
3900  * Rather than retail removal, just re-init the head after we've run
3901  * through the list.
3902  */
3903  dlist_init(&sxact->predicateLocks);
3904 
3905  if (IsInParallelMode())
3907  LWLockRelease(SerializablePredicateListLock);
3908 
3909  sxidtag.xid = sxact->topXid;
3910  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3911 
3912  /* Release all outConflicts (unless 'partial' is true) */
3913  if (!partial)
3914  {
3915  dlist_foreach_modify(iter, &sxact->outConflicts)
3916  {
3917  RWConflict conflict =
3918  dlist_container(RWConflictData, outLink, iter.cur);
3919 
3920  if (summarize)
3922  ReleaseRWConflict(conflict);
3923  }
3924  }
3925 
3926  /* Release all inConflicts. */
3927  dlist_foreach_modify(iter, &sxact->inConflicts)
3928  {
3929  RWConflict conflict =
3930  dlist_container(RWConflictData, inLink, iter.cur);
3931 
3932  if (summarize)
3934  ReleaseRWConflict(conflict);
3935  }
3936 
3937  /* Finally, get rid of the xid and the record of the transaction itself. */
3938  if (!partial)
3939  {
3940  if (sxidtag.xid != InvalidTransactionId)
3941  hash_search(SerializableXidHash, &sxidtag, HASH_REMOVE, NULL);
3942  ReleasePredXact(sxact);
3943  }
3944 
3945  LWLockRelease(SerializableXactHashLock);
3946 }
#define SxactIsOnFinishedList(sxact)
Definition: predicate.c:267
#define SxactIsRolledBack(sxact)
Definition: predicate.c:279

References Assert, SERIALIZABLEXACT::commitSeqNo, PREDICATELOCK::commitSeqNo, dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_foreach_modify, dlist_init(), dlist_push_tail(), ereport, errcode(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, HASH_ENTER_NULL, HASH_REMOVE, hash_search(), hash_search_with_hash_value(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, InvalidTransactionId, IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, OldCommittedSxact, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::perXactPredicateListLock, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetTagHashCode, ReleasePredXact(), ReleaseRWConflict(), RemoveTargetIfNoLongerUsed(), SerializableXidHash, 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 3297 of file predicate.c.

3298 {
3299  bool partiallyReleasing = false;
3300  bool needToClear;
3301  SERIALIZABLEXACT *roXact;
3302  dlist_mutable_iter iter;
3303 
3304  /*
3305  * We can't trust XactReadOnly here, because a transaction which started
3306  * as READ WRITE can show as READ ONLY later, e.g., within
3307  * subtransactions. We want to flag a transaction as READ ONLY if it
3308  * commits without writing so that de facto READ ONLY transactions get the
3309  * benefit of some RO optimizations, so we will use this local variable to
3310  * get some cleanup logic right which is based on whether the transaction
3311  * was declared READ ONLY at the top level.
3312  */
3313  bool topLevelIsDeclaredReadOnly;
3314 
3315  /* We can't be both committing and releasing early due to RO_SAFE. */
3316  Assert(!(isCommit && isReadOnlySafe));
3317 
3318  /* Are we at the end of a transaction, that is, a commit or abort? */
3319  if (!isReadOnlySafe)
3320  {
3321  /*
3322  * Parallel workers mustn't release predicate locks at the end of
3323  * their transaction. The leader will do that at the end of its
3324  * transaction.
3325  */
3326  if (IsParallelWorker())
3327  {
3329  return;
3330  }
3331 
3332  /*
3333  * By the time the leader in a parallel query reaches end of
3334  * transaction, it has waited for all workers to exit.
3335  */
3337 
3338  /*
3339  * If the leader in a parallel query earlier stashed a partially
3340  * released SERIALIZABLEXACT for final clean-up at end of transaction
3341  * (because workers might still have been accessing it), then it's
3342  * time to restore it.
3343  */
3345  {
3350  }
3351  }
3352 
3354  {
3355  Assert(LocalPredicateLockHash == NULL);
3356  return;
3357  }
3358 
3359  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3360 
3361  /*
3362  * If the transaction is committing, but it has been partially released
3363  * already, then treat this as a roll back. It was marked as rolled back.
3364  */
3366  isCommit = false;
3367 
3368  /*
3369  * If we're called in the middle of a transaction because we discovered
3370  * that the SXACT_FLAG_RO_SAFE flag was set, then we'll partially release
3371  * it (that is, release the predicate locks and conflicts, but not the
3372  * SERIALIZABLEXACT itself) if we're the first backend to have noticed.
3373  */
3374  if (isReadOnlySafe && IsInParallelMode())
3375  {
3376  /*
3377  * The leader needs to stash a pointer to it, so that it can
3378  * completely release it at end-of-transaction.
3379  */
3380  if (!IsParallelWorker())
3382 
3383  /*
3384  * The first backend to reach this condition will partially release
3385  * the SERIALIZABLEXACT. All others will just clear their
3386  * backend-local state so that they stop doing SSI checks for the rest
3387  * of the transaction.
3388  */
3390  {
3391  LWLockRelease(SerializableXactHashLock);
3393  return;
3394  }
3395  else
3396  {
3398  partiallyReleasing = true;
3399  /* ... and proceed to perform the partial release below. */
3400  }
3401  }
3402  Assert(!isCommit || SxactIsPrepared(MySerializableXact));
3403  Assert(!isCommit || !SxactIsDoomed(MySerializableXact));
3407 
3408  /* may not be serializable during COMMIT/ROLLBACK PREPARED */
3410 
3411  /* We'd better not already be on the cleanup list. */
3413 
3414  topLevelIsDeclaredReadOnly = SxactIsReadOnly(MySerializableXact);
3415 
3416  /*
3417  * We don't hold XidGenLock lock here, assuming that TransactionId is
3418  * atomic!
3419  *
3420  * If this value is changing, we don't care that much whether we get the
3421  * old or new value -- it is just used to determine how far
3422  * SxactGlobalXmin must advance before this transaction can be fully
3423  * cleaned up. The worst that could happen is we wait for one more
3424  * transaction to complete before freeing some RAM; correctness of visible
3425  * behavior is not affected.
3426  */
3428 
3429  /*
3430  * If it's not a commit it's either a rollback or a read-only transaction
3431  * flagged SXACT_FLAG_RO_SAFE, and we can clear our locks immediately.
3432  */
3433  if (isCommit)
3434  {
3437  /* Recognize implicit read-only transaction (commit without write). */
3438  if (!MyXactDidWrite)
3440  }
3441  else
3442  {
3443  /*
3444  * The DOOMED flag indicates that we intend to roll back this
3445  * transaction and so it should not cause serialization failures for
3446  * other transactions that conflict with it. Note that this flag might
3447  * already be set, if another backend marked this transaction for
3448  * abort.
3449  *
3450  * The ROLLED_BACK flag further indicates that ReleasePredicateLocks
3451  * has been called, and so the SerializableXact is eligible for
3452  * cleanup. This means it should not be considered when calculating
3453  * SxactGlobalXmin.
3454  */
3457 
3458  /*
3459  * If the transaction was previously prepared, but is now failing due
3460  * to a ROLLBACK PREPARED or (hopefully very rare) error after the
3461  * prepare, clear the prepared flag. This simplifies conflict
3462  * checking.
3463  */
3465  }
3466 
3467  if (!topLevelIsDeclaredReadOnly)
3468  {
3470  if (--(PredXact->WritableSxactCount) == 0)
3471  {
3472  /*
3473  * Release predicate locks and rw-conflicts in for all committed
3474  * transactions. There are no longer any transactions which might
3475  * conflict with the locks and no chance for new transactions to
3476  * overlap. Similarly, existing conflicts in can't cause pivots,
3477  * and any conflicts in which could have completed a dangerous
3478  * structure would already have caused a rollback, so any
3479  * remaining ones must be benign.
3480  */
3482  }
3483  }
3484  else
3485  {
3486  /*
3487  * Read-only transactions: clear the list of transactions that might
3488  * make us unsafe. Note that we use 'inLink' for the iteration as
3489  * opposed to 'outLink' for the r/w xacts.
3490  */
3492  {
3493  RWConflict possibleUnsafeConflict =
3494  dlist_container(RWConflictData, inLink, iter.cur);
3495 
3496  Assert(!SxactIsReadOnly(possibleUnsafeConflict->sxactOut));
3497  Assert(MySerializableXact == possibleUnsafeConflict->sxactIn);
3498 
3499  ReleaseRWConflict(possibleUnsafeConflict);
3500  }
3501  }
3502 
3503  /* Check for conflict out to old committed transactions. */
3504  if (isCommit
3507  {
3508  /*
3509  * we don't know which old committed transaction we conflicted with,
3510  * so be conservative and use FirstNormalSerCommitSeqNo here
3511  */
3515  }
3516 
3517  /*
3518  * Release all outConflicts to committed transactions. If we're rolling
3519  * back clear them all. Set SXACT_FLAG_CONFLICT_OUT if any point to
3520  * previously committed transactions.
3521  */
3523  {
3524  RWConflict conflict =
3525  dlist_container(RWConflictData, outLink, iter.cur);
3526 
3527  if (isCommit
3529  && SxactIsCommitted(conflict->sxactIn))
3530  {
3535  }
3536 
3537  if (!isCommit
3538  || SxactIsCommitted(conflict->sxactIn)
3540  ReleaseRWConflict(conflict);
3541  }
3542 
3543  /*
3544  * Release all inConflicts from committed and read-only transactions. If
3545  * we're rolling back, clear them all.
3546  */
3548  {
3549  RWConflict conflict =
3550  dlist_container(RWConflictData, inLink, iter.cur);
3551 
3552  if (!isCommit
3553  || SxactIsCommitted(conflict->sxactOut)
3554  || SxactIsReadOnly(conflict->sxactOut))
3555  ReleaseRWConflict(conflict);
3556  }
3557 
3558  if (!topLevelIsDeclaredReadOnly)
3559  {
3560  /*
3561  * Remove ourselves from the list of possible conflicts for concurrent
3562  * READ ONLY transactions, flagging them as unsafe if we have a
3563  * conflict out. If any are waiting DEFERRABLE transactions, wake them
3564  * up if they are known safe or known unsafe.
3565  */
3567  {
3568  RWConflict possibleUnsafeConflict =
3569  dlist_container(RWConflictData, outLink, iter.cur);
3570 
3571  roXact = possibleUnsafeConflict->sxactIn;
3572  Assert(MySerializableXact == possibleUnsafeConflict->sxactOut);
3573  Assert(SxactIsReadOnly(roXact));
3574 
3575  /* Mark conflicted if necessary. */
3576  if (isCommit
3577  && MyXactDidWrite
3580  <= roXact->SeqNo.lastCommitBeforeSnapshot))
3581  {
3582  /*
3583  * This releases possibleUnsafeConflict (as well as all other
3584  * possible conflicts for roXact)
3585  */
3586  FlagSxactUnsafe(roXact);
3587  }
3588  else
3589  {
3590  ReleaseRWConflict(possibleUnsafeConflict);
3591 
3592  /*
3593  * If we were the last possible conflict, flag it safe. The
3594  * transaction can now safely release its predicate locks (but
3595  * that transaction's backend has to do that itself).
3596  */
3598  roXact->flags |= SXACT_FLAG_RO_SAFE;
3599  }
3600 
3601  /*
3602  * Wake up the process for a waiting DEFERRABLE transaction if we
3603  * now know it's either safe or conflicted.
3604  */
3605  if (SxactIsDeferrableWaiting(roXact) &&
3606  (SxactIsROUnsafe(roXact) || SxactIsROSafe(roXact)))
3607  ProcSendSignal(roXact->pgprocno);
3608  }
3609  }
3610 
3611  /*
3612  * Check whether it's time to clean up old transactions. This can only be
3613  * done when the last serializable transaction with the oldest xmin among
3614  * serializable transactions completes. We then find the "new oldest"
3615  * xmin and purge any transactions which finished before this transaction
3616  * was launched.
3617  *
3618  * For parallel queries in read-only transactions, it might run twice. We
3619  * only release the reference on the first call.
3620  */
3621  needToClear = false;
3622  if ((partiallyReleasing ||
3626  {
3628  if (--(PredXact->SxactGlobalXminCount) == 0)
3629  {
3631  needToClear = true;
3632  }
3633  }
3634 
3635  LWLockRelease(SerializableXactHashLock);
3636 
3637  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3638 
3639  /* Add this to the list of transactions to check for later cleanup. */
3640  if (isCommit)
3643 
3644  /*
3645  * If we're releasing a RO_SAFE transaction in parallel mode, we'll only
3646  * partially release it. That's necessary because other backends may have
3647  * a reference to it. The leader will release the SERIALIZABLEXACT itself
3648  * at the end of the transaction after workers have stopped running.
3649  */
3650  if (!isCommit)
3652  isReadOnlySafe && IsInParallelMode(),
3653  false);
3654 
3655  LWLockRelease(SerializableFinishedListLock);
3656 
3657  if (needToClear)
3659 
3661 }
static void SetNewSxactGlobalXmin(void)
Definition: predicate.c:3236
static void ReleasePredicateLocksLocal(void)
Definition: predicate.c:3664
static void ClearOldPredicateLocks(void)
Definition: predicate.c:3682
static void FlagSxactUnsafe(SERIALIZABLEXACT *sxact)
Definition: predicate.c:699
static SERIALIZABLEXACT * SavedSerializableXact
Definition: predicate.c:431
#define SXACT_FLAG_CONFLICT_OUT
#define SXACT_FLAG_ROLLED_BACK
#define SXACT_FLAG_PARTIALLY_RELEASED
#define SXACT_FLAG_RO_SAFE
void ProcSendSignal(ProcNumber procNumber)
Definition: proc.c:1878
FullTransactionId nextXid
Definition: transam.h:220
#define XidFromFullTransactionId(x)
Definition: transam.h:48
TransamVariablesData * TransamVariables
Definition: varsup.c:34

References Assert, PredXactListData::CanPartialClearThrough, ClearOldPredicateLocks(), SERIALIZABLEXACT::commitSeqNo, dlist_mutable_iter::cur, dlist_container, dlist_foreach_modify, dlist_is_empty(), dlist_push_tail(), SERIALIZABLEXACT::earliestOutConflictCommit, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, FirstNormalSerCommitSeqNo, SERIALIZABLEXACT::flags, FlagSxactUnsafe(), SERIALIZABLEXACT::inConflicts, InvalidSerializableXact, IsInParallelMode(), IsolationIsSerializable, IsParallelWorker, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, LocalPredicateLockHash, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, MyXactDidWrite, TransamVariablesData::nextXid, SERIALIZABLEXACT::outConflicts, ParallelContextActive(), SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, PredXact, SERIALIZABLEXACT::prepareSeqNo, ProcSendSignal(), ReleaseOneSerializableXact(), ReleasePredicateLocksLocal(), ReleaseRWConflict(), SavedSerializableXact, SERIALIZABLEXACT::SeqNo, SetNewSxactGlobalXmin(), 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, TransamVariables, PredXactListData::WritableSxactCount, XidFromFullTransactionId, and SERIALIZABLEXACT::xmin.

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

◆ ReleasePredicateLocksLocal()

static void ReleasePredicateLocksLocal ( void  )
static

Definition at line 3664 of file predicate.c.

3665 {
3667  MyXactDidWrite = false;
3668 
3669  /* Delete per-transaction lock table */
3670  if (LocalPredicateLockHash != NULL)
3671  {
3673  LocalPredicateLockHash = NULL;
3674  }
3675 }

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

Referenced by ReleasePredicateLocks().

◆ ReleasePredXact()

static void ReleasePredXact ( SERIALIZABLEXACT sxact)
static

Definition at line 596 of file predicate.c.

597 {
598  Assert(ShmemAddrIsValid(sxact));
599 
600  dlist_delete(&sxact->xactLink);
602 }
bool ShmemAddrIsValid(const void *addr)
Definition: shmem.c:274

References Assert, PredXactListData::availableList, dlist_delete(), dlist_push_tail(), PredXact, ShmemAddrIsValid(), and SERIALIZABLEXACT::xactLink.

Referenced by GetSerializableTransactionSnapshotInt(), and ReleaseOneSerializableXact().

◆ ReleaseRWConflict()

static void ReleaseRWConflict ( RWConflict  conflict)
static

◆ RemoveScratchTarget()

static void RemoveScratchTarget ( bool  lockheld)
static

Definition at line 2125 of file predicate.c.

2126 {
2127  bool found;
2128 
2129  Assert(LWLockHeldByMe(SerializablePredicateListLock));
2130 
2131  if (!lockheld)
2136  HASH_REMOVE, &found);
2137  Assert(found);
2138  if (!lockheld)
2140 }

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

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

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

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

◆ RestoreScratchTarget()

static void RestoreScratchTarget ( bool  lockheld)
static

Definition at line 2146 of file predicate.c.

2147 {
2148  bool found;
2149 
2150  Assert(LWLockHeldByMe(SerializablePredicateListLock));
2151 
2152  if (!lockheld)
2157  HASH_ENTER, &found);
2158  Assert(!found);
2159  if (!lockheld)
2161 }

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

611 {
612  dlist_iter iter;
613 
614  Assert(reader != writer);
615 
616  /* Check the ends of the purported conflict first. */
617  if (SxactIsDoomed(reader)
618  || SxactIsDoomed(writer)
619  || dlist_is_empty(&reader->outConflicts)
620  || dlist_is_empty(&writer->inConflicts))
621  return false;
622 
623  /*
624  * A conflict is possible; walk the list to find out.
625  *
626  * The unconstify is needed as we have no const version of
627  * dlist_foreach().
628  */
629  dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->outConflicts)
630  {
631  RWConflict conflict =
632  dlist_container(RWConflictData, outLink, iter.cur);
633 
634  if (conflict->sxactIn == writer)
635  return true;
636  }
637 
638  /* No conflict found. */
639  return false;
640 }

References Assert, dlist_iter::cur, dlist_container, dlist_foreach, dlist_is_empty(), SERIALIZABLEXACT::inConflicts, SERIALIZABLEXACT::outConflicts, RWConflictData::sxactIn, SxactIsDoomed, and unconstify.

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

◆ SerialAdd()

static void SerialAdd ( TransactionId  xid,
SerCommitSeqNo  minConflictCommitSeqNo 
)
static

Definition at line 858 of file predicate.c.

859 {
860  TransactionId tailXid;
861  int64 targetPage;
862  int slotno;
863  int64 firstZeroPage;
864  bool isNewPage;
865  LWLock *lock;
866 
868 
869  targetPage = SerialPage(xid);
870  lock = SimpleLruGetBankLock(SerialSlruCtl, targetPage);
871 
872  /*
873  * In this routine, we must hold both SerialControlLock and the SLRU bank
874  * lock simultaneously while making the SLRU data catch up with the new
875  * state that we determine.
876  */
877  LWLockAcquire(SerialControlLock, LW_EXCLUSIVE);
878 
879  /*
880  * If no serializable transactions are active, there shouldn't be anything
881  * to push out to the SLRU. Hitting this assert would mean there's
882  * something wrong with the earlier cleanup logic.
883  */
884  tailXid = serialControl->tailXid;
885  Assert(TransactionIdIsValid(tailXid));
886 
887  /*
888  * If the SLRU is currently unused, zero out the whole active region from
889  * tailXid to headXid before taking it into use. Otherwise zero out only
890  * any new pages that enter the tailXid-headXid range as we advance
891  * headXid.
892  */
893  if (serialControl->headPage < 0)
894  {
895  firstZeroPage = SerialPage(tailXid);
896  isNewPage = true;
897  }
898  else
899  {
900  firstZeroPage = SerialNextPage(serialControl->headPage);
902  targetPage);
903  }
904 
907  serialControl->headXid = xid;
908  if (isNewPage)
909  serialControl->headPage = targetPage;
910 
911  if (isNewPage)
912  {
913  /* Initialize intervening pages; might involve trading locks */
914  for (;;)
915  {
916  lock = SimpleLruGetBankLock(SerialSlruCtl, firstZeroPage);
918  slotno = SimpleLruZeroPage(SerialSlruCtl, firstZeroPage);
919  if (firstZeroPage == targetPage)
920  break;
921  firstZeroPage = SerialNextPage(firstZeroPage);
922  LWLockRelease(lock);
923  }
924  }
925  else
926  {
928  slotno = SimpleLruReadPage(SerialSlruCtl, targetPage, true, xid);
929  }
930 
931  SerialValue(slotno, xid) = minConflictCommitSeqNo;
932  SerialSlruCtl->shared->page_dirty[slotno] = true;
933 
934  LWLockRelease(lock);
935  LWLockRelease(SerialControlLock);
936 }
uint32 TransactionId
Definition: c.h:652
#define SerialNextPage(page)
Definition: predicate.c:337
#define SerialValue(slotno, xid)
Definition: predicate.c:339
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition: slru.c:487
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:360
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:179
TransactionId headXid
Definition: predicate.c:348

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

Referenced by SummarizeOldestCommittedSxact().

◆ SerialGetMinConflictCommitSeqNo()

static SerCommitSeqNo SerialGetMinConflictCommitSeqNo ( TransactionId  xid)
static

Definition at line 944 of file predicate.c.

945 {
946  TransactionId headXid;
947  TransactionId tailXid;
949  int slotno;
950 
952 
953  LWLockAcquire(SerialControlLock, LW_SHARED);
954  headXid = serialControl->headXid;
955  tailXid = serialControl->tailXid;
956  LWLockRelease(SerialControlLock);
957 
958  if (!TransactionIdIsValid(headXid))
959  return 0;
960 
961  Assert(TransactionIdIsValid(tailXid));
962 
963  if (TransactionIdPrecedes(xid, tailXid)
964  || TransactionIdFollows(xid, headXid))
965  return 0;
966 
967  /*
968  * The following function must be called without holding SLRU bank lock,
969  * but will return with that lock held, which must then be released.
970  */
972  SerialPage(xid), xid);
973  val = SerialValue(slotno, xid);
975  return val;
976 }
long val
Definition: informix.c:670
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:590

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

Referenced by CheckForSerializableConflictOut().

◆ SerialInit()

static void SerialInit ( void  )
static

Definition at line 806 of file predicate.c.

807 {
808  bool found;
809 
810  /*
811  * Set up SLRU management of the pg_serial data.
812  */
814  SimpleLruInit(SerialSlruCtl, "serializable",
815  serializable_buffers, 0, "pg_serial",
817  SYNC_HANDLER_NONE, false);
818 #ifdef USE_ASSERT_CHECKING
819  SerialPagePrecedesLogicallyUnitTests();
820 #endif
822 
823  /*
824  * Create or attach to the SerialControl structure.
825  */
827  ShmemInitStruct("SerialControlData", sizeof(SerialControlData), &found);
828 
829  Assert(found == IsUnderPostmaster);
830  if (!found)
831  {
832  /*
833  * Set control information to reflect empty SLRU.
834  */
835  LWLockAcquire(SerialControlLock, LW_EXCLUSIVE);
836  serialControl->headPage = -1;
839  LWLockRelease(SerialControlLock);
840  }
841 }
@ LWTRANCHE_SERIAL_SLRU
Definition: lwlock.h:214
@ LWTRANCHE_SERIAL_BUFFER
Definition: lwlock.h:185
struct SerialControlData * SerialControl
Definition: predicate.c:352
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, const char *subdir, int buffer_tranche_id, int bank_tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
Definition: slru.c:237
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:203
@ SYNC_HANDLER_NONE
Definition: sync.h:42

References Assert, SerialControlData::headPage, SerialControlData::headXid, InvalidTransactionId, IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), LWTRANCHE_SERIAL_BUFFER, LWTRANCHE_SERIAL_SLRU, SERIAL_ENTRIESPERPAGE, serialControl, serializable_buffers, SerialPagePrecedesLogically(), SerialSlruCtl, ShmemInitStruct(), SimpleLruInit(), SlruPagePrecedesUnitTests, SYNC_HANDLER_NONE, and SerialControlData::tailXid.

Referenced by InitPredicateLocks().

◆ SerializationNeededForRead()

static bool SerializationNeededForRead ( Relation  relation,
Snapshot  snapshot 
)
inlinestatic

Definition at line 516 of file predicate.c.

517 {
518  /* Nothing to do if this is not a serializable transaction */
520  return false;
521 
522  /*
523  * Don't acquire locks or conflict when scanning with a special snapshot.
524  * This excludes things like CLUSTER and REINDEX. They use the wholesale
525  * functions TransferPredicateLocksToHeapRelation() and
526  * CheckTableForSerializableConflictIn() to participate in serialization,
527  * but the scans involved don't need serialization.
528  */
529  if (!IsMVCCSnapshot(snapshot))
530  return false;
531 
532  /*
533  * Check if we have just become "RO-safe". If we have, immediately release
534  * all locks as they're not needed anymore. This also resets
535  * MySerializableXact, so that subsequent calls to this function can exit
536  * quickly.
537  *
538  * A transaction is flagged as RO_SAFE if all concurrent R/W transactions
539  * commit without having conflicts out to an earlier snapshot, thus
540  * ensuring that no conflicts are possible for this transaction.
541  */
543  {
544  ReleasePredicateLocks(false, true);
545  return false;
546  }
547 
548  /* Check if the relation doesn't participate in predicate locking */
549  if (!PredicateLockingNeededForRelation(relation))
550  return false;
551 
552  return true; /* no excuse to skip predicate locking */
553 }
#define IsMVCCSnapshot(snapshot)
Definition: snapmgr.h:62

References InvalidSerializableXact, IsMVCCSnapshot, MySerializableXact, PredicateLockingNeededForRelation(), ReleasePredicateLocks(), and SxactIsROSafe.

Referenced by CheckForSerializableConflictOut(), CheckForSerializableConflictOutNeeded(), PredicateLockPage(), PredicateLockRelation(), and PredicateLockTID().

◆ SerializationNeededForWrite()

static bool SerializationNeededForWrite ( Relation  relation)
inlinestatic

Definition at line 560 of file predicate.c.

561 {
562  /* Nothing to do if this is not a serializable transaction */
564  return false;
565 
566  /* Check if the relation doesn't participate in predicate locking */
567  if (!PredicateLockingNeededForRelation(relation))
568  return false;
569 
570  return true; /* no excuse to skip predicate locking */
571 }

References InvalidSerializableXact, MySerializableXact, and PredicateLockingNeededForRelation().

Referenced by CheckForSerializableConflictIn(), and CheckTableForSerializableConflictIn().

◆ SerialPagePrecedesLogically()

static bool SerialPagePrecedesLogically ( int64  page1,
int64  page2 
)
static

Definition at line 731 of file predicate.c.

732 {
733  TransactionId xid1;
734  TransactionId xid2;
735 
736  xid1 = ((TransactionId) page1) * SERIAL_ENTRIESPERPAGE;
737  xid1 += FirstNormalTransactionId + 1;
738  xid2 = ((TransactionId) page2) * SERIAL_ENTRIESPERPAGE;
739  xid2 += FirstNormalTransactionId + 1;
740 
741  return (TransactionIdPrecedes(xid1, xid2) &&
742  TransactionIdPrecedes(xid1, xid2 + SERIAL_ENTRIESPERPAGE - 1));
743 }
#define FirstNormalTransactionId
Definition: transam.h:34

References FirstNormalTransactionId, SERIAL_ENTRIESPERPAGE, and TransactionIdPrecedes().

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

◆ SerialSetActiveSerXmin()

static void SerialSetActiveSerXmin ( TransactionId  xid)
static

Definition at line 985 of file predicate.c.