PostgreSQL Source Code  git master
predicate.h File Reference
#include "storage/lock.h"
#include "utils/relcache.h"
#include "utils/snapshot.h"
Include dependency graph for predicate.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef void * SerializableXactHandle
 

Functions

void PredicateLockShmemInit (void)
 
Size PredicateLockShmemSize (void)
 
void CheckPointPredicate (void)
 
bool PageIsPredicateLocked (Relation relation, BlockNumber blkno)
 
Snapshot GetSerializableTransactionSnapshot (Snapshot snapshot)
 
void SetSerializableTransactionSnapshot (Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
 
void RegisterPredicateLockingXid (TransactionId xid)
 
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 PredicateLockPageSplit (Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
 
void PredicateLockPageCombine (Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
 
void TransferPredicateLocksToHeapRelation (Relation relation)
 
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

PGDLLIMPORT int max_predicate_locks_per_xact
 
PGDLLIMPORT int max_predicate_locks_per_relation
 
PGDLLIMPORT int max_predicate_locks_per_page
 

Typedef Documentation

◆ SerializableXactHandle

typedef void* SerializableXactHandle

Definition at line 33 of file predicate.h.

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:861
#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:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ 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::@118 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().

◆ 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 }
#define InvalidBlockNumber
Definition: block.h:33
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:853
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 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
@ 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
uint64 SerCommitSeqNo
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
SerCommitSeqNo lastCommitBeforeSnapshot
union SERIALIZABLEXACT::@117 SeqNo
SerCommitSeqNo earliestOutConflictCommit
SERIALIZABLEXACT * myXact
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:440

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  int64 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  int64 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
#define SerialSlruCtl
Definition: predicate.c:326
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1322
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition: slru.c:1408
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:1420
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
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
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().

◆ 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
#define InvalidPid
Definition: miscadmin.h:32
static Snapshot GetSafeSnapshot(Snapshot origSnapshot)
Definition: predicate.c:1543
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1749
bool XactDeferrable
Definition: xact.c:84
bool XactReadOnly
Definition: xact.c:81
#define IsolationIsSerializable()
Definition: xact.h:52
bool RecoveryInProgress(void)
Definition: xlog.c:6333

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

Referenced by GetTransactionSnapshot().

◆ 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 }
unsigned int uint32
Definition: c.h:509
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:968
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:303
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:258
Definition: lwlock.h:42

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
SerCommitSeqNo LastSxactCommitSeqNo
SERIALIZABLEXACT * sxactOut
SerCommitSeqNo prepareSeqNo

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_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:657
int MaxBackends
Definition: globals.c:145
@ HASH_ENTER
Definition: hsearch.h:114
static void dlist_init(dlist_head *head)
Definition: ilist.h:314
static void dlist_node_init(dlist_node *node)
Definition: ilist.h:325
const void size_t len
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2438
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:582
static void SerialSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:985
#define SXACT_FLAG_SUMMARY_CONFLICT_IN
#define RecoverySerCommitSeqNo
VirtualTransactionId vxid
dlist_head possibleUnsafeConflicts
SerCommitSeqNo commitSeqNo
TransactionId finishedBefore
LocalTransactionId localTransactionId
Definition: lock.h:62
ProcNumber procNumber
Definition: lock.h:61
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 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.

◆ PredicateLockPage()

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

Definition at line 2584 of file predicate.c.

2585 {
2587 
2588  if (!SerializationNeededForRead(relation, snapshot))
2589  return;
2590 
2592  relation->rd_locator.dbOid,
2593  relation->rd_id,
2594  blkno);
2595  PredicateLockAcquire(&tag);
2596 }
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2502

References RelFileLocator::dbOid, PredicateLockAcquire(), RelationData::rd_id, RelationData::rd_locator, SerializationNeededForRead(), and SET_PREDICATELOCKTARGETTAG_PAGE.

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

◆ 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 PredicateLockingNeededForRelation(Relation relation)
Definition: predicate.c:498
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:2057
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().

◆ PredicateLockShmemInit()

void PredicateLockShmemInit ( 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:608
bool IsUnderPostmaster
Definition: globals.c:119
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_FUNCTION
Definition: hsearch.h:98
#define HASH_BLOBS
Definition: hsearch.h:97
#define HASH_FIXED_SIZE
Definition: hsearch.h:105
#define HASH_PARTITION
Definition: hsearch.h:92
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:74
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:707
@ LWTRANCHE_PER_XACT_PREDICATE_LIST
Definition: lwlock.h:202
static HTAB * PredicateLockHash
Definition: predicate.c:398
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 SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:362
static void SerialInit(void)
Definition: predicate.c:806
static dlist_head * FinishedSerializableTransactions
Definition: predicate.c:399
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 PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
struct SERIALIZABLEXID SERIALIZABLEXID
#define SXACT_FLAG_COMMITTED
struct PREDICATELOCK PREDICATELOCK
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
Size keysize
Definition: hsearch.h:75
HashValueFunc hash
Definition: hsearch.h:78
Size entrysize
Definition: hsearch.h:76
long num_partitions
Definition: hsearch.h:68
SERIALIZABLEXACT * element
SerCommitSeqNo CanPartialClearThrough
SERIALIZABLEXACT * OldCommittedSxact
SerCommitSeqNo HavePartialClearedThrough

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

◆ 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:164
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:199

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 }
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2030
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:940

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 }
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3297

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

◆ 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
#define SxactIsROUnsafe(sxact)
Definition: predicate.c:292
#define SxactIsDeferrableWaiting(sxact)
Definition: predicate.c:290
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
#define SxactIsOnFinishedList(sxact)
Definition: predicate.c:267
#define SxactIsROSafe(sxact)
Definition: predicate.c:291
static void ReleaseRWConflict(RWConflict conflict)
Definition: predicate.c:691
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize)
Definition: predicate.c:3820
#define SxactIsRolledBack(sxact)
Definition: predicate.c:279
static SERIALIZABLEXACT * SavedSerializableXact
Definition: predicate.c:431
#define SXACT_FLAG_CONFLICT_OUT
#define SXACT_FLAG_READ_ONLY
#define SXACT_FLAG_ROLLED_BACK
#define SXACT_FLAG_PARTIALLY_RELEASED
#define SXACT_FLAG_RO_SAFE
void ProcSendSignal(ProcNumber procNumber)
Definition: proc.c:1918
SERIALIZABLEXACT * sxactIn
FullTransactionId nextXid
Definition: transam.h:220
#define XidFromFullTransactionId(x)
Definition: transam.h:48
TransamVariablesData * TransamVariables
Definition: varsup.c:34
bool IsInParallelMode(void)
Definition: xact.c:1088

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

◆ SetSerializableTransactionSnapshot()

void SetSerializableTransactionSnapshot ( Snapshot  snapshot,
VirtualTransactionId sourcevxid,
int  sourcepid 
)

Definition at line 1707 of file predicate.c.

1710 {
1712 
1713  /*
1714  * If this is called by parallel.c in a parallel worker, we don't want to
1715  * create a SERIALIZABLEXACT just yet because the leader's
1716  * SERIALIZABLEXACT will be installed with AttachSerializableXact(). We
1717  * also don't want to reject SERIALIZABLE READ ONLY DEFERRABLE in this
1718  * case, because the leader has already determined that the snapshot it
1719  * has passed us is safe. So there is nothing for us to do.
1720  */
1721  if (IsParallelWorker())
1722  return;
1723 
1724  /*
1725  * We do not allow SERIALIZABLE READ ONLY DEFERRABLE transactions to
1726  * import snapshots, since there's no way to wait for a safe snapshot when
1727  * we're using the snap we're told to. (XXX instead of throwing an error,
1728  * we could just ignore the XactDeferrable flag?)
1729  */
1731  ereport(ERROR,
1732  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1733  errmsg("a snapshot-importing transaction must not be READ ONLY DEFERRABLE")));
1734 
1735  (void) GetSerializableTransactionSnapshotInt(snapshot, sourcevxid,
1736  sourcepid);
1737 }

References Assert, ereport, errcode(), errmsg(), ERROR, GetSerializableTransactionSnapshotInt(), IsolationIsSerializable, IsParallelWorker, XactDeferrable, and XactReadOnly.

Referenced by SetTransactionSnapshot().

◆ ShareSerializableXact()

SerializableXactHandle ShareSerializableXact ( void  )

Definition at line 5031 of file predicate.c.

5032 {
5033  return MySerializableXact;
5034 }

References MySerializableXact.

Referenced by InitializeParallelDSM().

◆ TransferPredicateLocksToHeapRelation()

void TransferPredicateLocksToHeapRelation ( Relation  relation)

Definition at line 3108 of file predicate.c.

3109 {
3110  DropAllPredicateLocksFromTable(relation, true);
3111 }
static void DropAllPredicateLocksFromTable(Relation relation, bool transfer)
Definition: predicate.c:2922

References DropAllPredicateLocksFromTable().

Referenced by ATRewriteTable(), cluster_rel(), index_concurrently_set_dead(), index_drop(), and reindex_index().

Variable Documentation

◆ max_predicate_locks_per_page

PGDLLIMPORT int max_predicate_locks_per_page
extern

Definition at line 373 of file predicate.c.

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_relation

PGDLLIMPORT int max_predicate_locks_per_relation
extern

Definition at line 372 of file predicate.c.

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_xact

PGDLLIMPORT int max_predicate_locks_per_xact
extern

Definition at line 371 of file predicate.c.

Referenced by CreateLocalPredicateLockHash(), and MaxPredicateChildLocks().