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 InitPredicateLocks (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 4770 of file predicate.c.

4771 {
4772  SERIALIZABLEXACT *sxact;
4773  TwoPhasePredicateRecord record;
4774  TwoPhasePredicateXactRecord *xactRecord;
4775  TwoPhasePredicateLockRecord *lockRecord;
4776  dlist_iter iter;
4777 
4778  sxact = MySerializableXact;
4779  xactRecord = &(record.data.xactRecord);
4780  lockRecord = &(record.data.lockRecord);
4781 
4783  return;
4784 
4785  /* Generate an xact record for our SERIALIZABLEXACT */
4787  xactRecord->xmin = MySerializableXact->xmin;
4788  xactRecord->flags = MySerializableXact->flags;
4789 
4790  /*
4791  * Note that we don't include the list of conflicts in our out in the
4792  * statefile, because new conflicts can be added even after the
4793  * transaction prepares. We'll just make a conservative assumption during
4794  * recovery instead.
4795  */
4796 
4798  &record, sizeof(record));
4799 
4800  /*
4801  * Generate a lock record for each lock.
4802  *
4803  * To do this, we need to walk the predicate lock list in our sxact rather
4804  * than using the local predicate lock table because the latter is not
4805  * guaranteed to be accurate.
4806  */
4807  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4808 
4809  /*
4810  * No need to take sxact->perXactPredicateListLock in parallel mode
4811  * because there cannot be any parallel workers running while we are
4812  * preparing a transaction.
4813  */
4815 
4816  dlist_foreach(iter, &sxact->predicateLocks)
4817  {
4818  PREDICATELOCK *predlock =
4819  dlist_container(PREDICATELOCK, xactLink, iter.cur);
4820 
4822  lockRecord->target = predlock->tag.myTarget->tag;
4823 
4825  &record, sizeof(record));
4826  }
4827 
4828  LWLockRelease(SerializablePredicateListLock);
4829 }
bool ParallelContextActive(void)
Definition: parallel.c:1003
#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
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1172
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1785
@ LW_SHARED
Definition: lwlock.h:117
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::@111 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 5035 of file predicate.c.

5036 {
5037 
5039 
5040  MySerializableXact = (SERIALIZABLEXACT *) handle;
5043 }
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1920

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

Referenced by ParallelWorkerMain().

◆ CheckForSerializableConflictIn()

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

Definition at line 4316 of file predicate.c.

4317 {
4318  PREDICATELOCKTARGETTAG targettag;
4319 
4320  if (!SerializationNeededForWrite(relation))
4321  return;
4322 
4323  /* Check if someone else has already decided that we need to die */
4325  ereport(ERROR,
4327  errmsg("could not serialize access due to read/write dependencies among transactions"),
4328  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4329  errhint("The transaction might succeed if retried.")));
4330 
4331  /*
4332  * We're doing a write which might cause rw-conflicts now or later.
4333  * Memorize that fact.
4334  */
4335  MyXactDidWrite = true;
4336 
4337  /*
4338  * It is important that we check for locks from the finest granularity to
4339  * the coarsest granularity, so that granularity promotion doesn't cause
4340  * us to miss a lock. The new (coarser) lock will be acquired before the
4341  * old (finer) locks are released.
4342  *
4343  * It is not possible to take and hold a lock across the checks for all
4344  * granularities because each target could be in a separate partition.
4345  */
4346  if (tid != NULL)
4347  {
4349  relation->rd_locator.dbOid,
4350  relation->rd_id,
4353  CheckTargetForConflictsIn(&targettag);
4354  }
4355 
4356  if (blkno != InvalidBlockNumber)
4357  {
4359  relation->rd_locator.dbOid,
4360  relation->rd_id,
4361  blkno);
4362  CheckTargetForConflictsIn(&targettag);
4363  }
4364 
4366  relation->rd_locator.dbOid,
4367  relation->rd_id);
4368  CheckTargetForConflictsIn(&targettag);
4369 }
#define InvalidBlockNumber
Definition: block.h:33
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1232
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#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:4146
#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 4003 of file predicate.c.

4004 {
4005  SERIALIZABLEXIDTAG sxidtag;
4006  SERIALIZABLEXID *sxid;
4007  SERIALIZABLEXACT *sxact;
4008 
4009  if (!SerializationNeededForRead(relation, snapshot))
4010  return;
4011 
4012  /* Check if someone else has already decided that we need to die */
4014  {
4015  ereport(ERROR,
4017  errmsg("could not serialize access due to read/write dependencies among transactions"),
4018  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4019  errhint("The transaction might succeed if retried.")));
4020  }
4022 
4024  return;
4025 
4026  /*
4027  * Find sxact or summarized info for the top level xid.
4028  */
4029  sxidtag.xid = xid;
4030  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4031  sxid = (SERIALIZABLEXID *)
4032  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4033  if (!sxid)
4034  {
4035  /*
4036  * Transaction not found in "normal" SSI structures. Check whether it
4037  * got pushed out to SLRU storage for "old committed" transactions.
4038  */
4039  SerCommitSeqNo conflictCommitSeqNo;
4040 
4041  conflictCommitSeqNo = SerialGetMinConflictCommitSeqNo(xid);
4042  if (conflictCommitSeqNo != 0)
4043  {
4044  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4046  || conflictCommitSeqNo
4048  ereport(ERROR,
4050  errmsg("could not serialize access due to read/write dependencies among transactions"),
4051  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4052  errhint("The transaction might succeed if retried.")));
4053 
4056  ereport(ERROR,
4058  errmsg("could not serialize access due to read/write dependencies among transactions"),
4059  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4060  errhint("The transaction might succeed if retried.")));
4061 
4063  }
4064 
4065  /* It's not serializable or otherwise not important. */
4066  LWLockRelease(SerializableXactHashLock);
4067  return;
4068  }
4069  sxact = sxid->myXact;
4070  Assert(TransactionIdEquals(sxact->topXid, xid));
4071  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4072  {
4073  /* Can't conflict with ourself or a transaction that will roll back. */
4074  LWLockRelease(SerializableXactHashLock);
4075  return;
4076  }
4077 
4078  /*
4079  * We have a conflict out to a transaction which has a conflict out to a
4080  * summarized transaction. That summarized transaction must have
4081  * committed first, and we can't tell when it committed in relation to our
4082  * snapshot acquisition, so something needs to be canceled.
4083  */
4084  if (SxactHasSummaryConflictOut(sxact))
4085  {
4086  if (!SxactIsPrepared(sxact))
4087  {
4088  sxact->flags |= SXACT_FLAG_DOOMED;
4089  LWLockRelease(SerializableXactHashLock);
4090  return;
4091  }
4092  else
4093  {
4094  LWLockRelease(SerializableXactHashLock);
4095  ereport(ERROR,
4097  errmsg("could not serialize access due to read/write dependencies among transactions"),
4098  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4099  errhint("The transaction might succeed if retried.")));
4100  }
4101  }
4102 
4103  /*
4104  * If this is a read-only transaction and the writing transaction has
4105  * committed, and it doesn't have a rw-conflict to a transaction which
4106  * committed before it, no conflict.
4107  */
4109  && SxactIsCommitted(sxact)
4110  && !SxactHasSummaryConflictOut(sxact)
4111  && (!SxactHasConflictOut(sxact)
4113  {
4114  /* Read-only transaction will appear to run first. No conflict. */
4115  LWLockRelease(SerializableXactHashLock);
4116  return;
4117  }
4118 
4119  if (!XidIsConcurrent(xid))
4120  {
4121  /* This write was already in our snapshot; no conflict. */
4122  LWLockRelease(SerializableXactHashLock);
4123  return;
4124  }
4125 
4127  {
4128  /* We don't want duplicate conflict records in the list. */
4129  LWLockRelease(SerializableXactHashLock);
4130  return;
4131  }
4132 
4133  /*
4134  * Flag the conflict. But first, if this conflict creates a dangerous
4135  * structure, ereport an error.
4136  */
4138  LWLockRelease(SerializableXactHashLock);
4139 }
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:116
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:4481
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:939
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:3952
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:283
#define InvalidSerCommitSeqNo
#define SXACT_FLAG_DOOMED
uint64 SerCommitSeqNo
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
SerCommitSeqNo lastCommitBeforeSnapshot
SerCommitSeqNo earliestOutConflictCommit
union SERIALIZABLEXACT::@110 SeqNo
SERIALIZABLEXACT * myXact
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:433

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

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

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

Referenced by HeapCheckForSerializableConflictOut().

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 1031 of file predicate.c.

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

4400 {
4401  HASH_SEQ_STATUS seqstat;
4402  PREDICATELOCKTARGET *target;
4403  Oid dbId;
4404  Oid heapId;
4405  int i;
4406 
4407  /*
4408  * Bail out quickly if there are no serializable transactions running.
4409  * It's safe to check this without taking locks because the caller is
4410  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4411  * would matter here can be acquired while that is held.
4412  */
4414  return;
4415 
4416  if (!SerializationNeededForWrite(relation))
4417  return;
4418 
4419  /*
4420  * We're doing a write which might cause rw-conflicts now or later.
4421  * Memorize that fact.
4422  */
4423  MyXactDidWrite = true;
4424 
4425  Assert(relation->rd_index == NULL); /* not an index relation */
4426 
4427  dbId = relation->rd_locator.dbOid;
4428  heapId = relation->rd_id;
4429 
4430  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
4431  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4433  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4434 
4435  /* Scan through target list */
4437 
4438  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4439  {
4440  dlist_mutable_iter iter;
4441 
4442  /*
4443  * Check whether this is a target which needs attention.
4444  */
4445  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4446  continue; /* wrong relation id */
4447  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4448  continue; /* wrong database id */
4449 
4450  /*
4451  * Loop through locks for this target and flag conflicts.
4452  */
4453  dlist_foreach_modify(iter, &target->predicateLocks)
4454  {
4455  PREDICATELOCK *predlock =
4456  dlist_container(PREDICATELOCK, targetLink, iter.cur);
4457 
4458  if (predlock->tag.myXact != MySerializableXact
4460  {
4462  }
4463  }
4464  }
4465 
4466  /* Release locks in reverse order */
4467  LWLockRelease(SerializableXactHashLock);
4468  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4470  LWLockRelease(SerializablePredicateListLock);
4471 }
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:103
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 1662 of file predicate.c.

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

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

Referenced by GetTransactionSnapshot().

◆ InitPredicateLocks()

void InitPredicateLocks ( void  )

Definition at line 1135 of file predicate.c.

1136 {
1137  HASHCTL info;
1138  long max_table_size;
1139  Size requestSize;
1140  bool found;
1141 
1142 #ifndef EXEC_BACKEND
1144 #endif
1145 
1146  /*
1147  * Compute size of predicate lock target hashtable. Note these
1148  * calculations must agree with PredicateLockShmemSize!
1149  */
1150  max_table_size = NPREDICATELOCKTARGETENTS();
1151 
1152  /*
1153  * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1154  * per-predicate-lock-target information.
1155  */
1156  info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1157  info.entrysize = sizeof(PREDICATELOCKTARGET);
1159 
1160  PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1161  max_table_size,
1162  max_table_size,
1163  &info,
1164  HASH_ELEM | HASH_BLOBS |
1166 
1167  /*
1168  * Reserve a dummy entry in the hash table; we use it to make sure there's
1169  * always one entry available when we need to split or combine a page,
1170  * because running out of space there could mean aborting a
1171  * non-serializable transaction.
1172  */
1173  if (!IsUnderPostmaster)
1174  {
1176  HASH_ENTER, &found);
1177  Assert(!found);
1178  }
1179 
1180  /* Pre-calculate the hash and partition lock of the scratch entry */
1183 
1184  /*
1185  * Allocate hash table for PREDICATELOCK structs. This stores per
1186  * xact-lock-of-a-target information.
1187  */
1188  info.keysize = sizeof(PREDICATELOCKTAG);
1189  info.entrysize = sizeof(PREDICATELOCK);
1190  info.hash = predicatelock_hash;
1192 
1193  /* Assume an average of 2 xacts per target */
1194  max_table_size *= 2;
1195 
1196  PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1197  max_table_size,
1198  max_table_size,
1199  &info,
1202 
1203  /*
1204  * Compute size for serializable transaction hashtable. Note these
1205  * calculations must agree with PredicateLockShmemSize!
1206  */
1207  max_table_size = (MaxBackends + max_prepared_xacts);
1208 
1209  /*
1210  * Allocate a list to hold information on transactions participating in
1211  * predicate locking.
1212  *
1213  * Assume an average of 10 predicate locking transactions per backend.
1214  * This allows aggressive cleanup while detail is present before data must
1215  * be summarized for storage in SLRU and the "dummy" transaction.
1216  */
1217  max_table_size *= 10;
1218 
1219  PredXact = ShmemInitStruct("PredXactList",
1221  &found);
1222  Assert(found == IsUnderPostmaster);
1223  if (!found)
1224  {
1225  int i;
1226 
1235  requestSize = mul_size((Size) max_table_size,
1236  sizeof(SERIALIZABLEXACT));
1237  PredXact->element = ShmemAlloc(requestSize);
1238  /* Add all elements to available list, clean. */
1239  memset(PredXact->element, 0, requestSize);
1240  for (i = 0; i < max_table_size; i++)
1241  {
1245  }
1262  }
1263  /* This never changes, so let's keep a local copy. */
1265 
1266  /*
1267  * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1268  * information for serializable transactions which have accessed data.
1269  */
1270  info.keysize = sizeof(SERIALIZABLEXIDTAG);
1271  info.entrysize = sizeof(SERIALIZABLEXID);
1272 
1273  SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1274  max_table_size,
1275  max_table_size,
1276  &info,
1277  HASH_ELEM | HASH_BLOBS |
1278  HASH_FIXED_SIZE);
1279 
1280  /*
1281  * Allocate space for tracking rw-conflicts in lists attached to the
1282  * transactions.
1283  *
1284  * Assume an average of 5 conflicts per transaction. Calculations suggest
1285  * that this will prevent resource exhaustion in even the most pessimal
1286  * loads up to max_connections = 200 with all 200 connections pounding the
1287  * database with serializable transactions. Beyond that, there may be
1288  * occasional transactions canceled when trying to flag conflicts. That's
1289  * probably OK.
1290  */
1291  max_table_size *= 5;
1292 
1293  RWConflictPool = ShmemInitStruct("RWConflictPool",
1295  &found);
1296  Assert(found == IsUnderPostmaster);
1297  if (!found)
1298  {
1299  int i;
1300 
1302  requestSize = mul_size((Size) max_table_size,
1304  RWConflictPool->element = ShmemAlloc(requestSize);
1305  /* Add all elements to available list, clean. */
1306  memset(RWConflictPool->element, 0, requestSize);
1307  for (i = 0; i < max_table_size; i++)
1308  {
1311  }
1312  }
1313 
1314  /*
1315  * Create or attach to the header for the list of finished serializable
1316  * transactions.
1317  */
1319  ShmemInitStruct("FinishedSerializableTransactions",
1320  sizeof(dlist_head),
1321  &found);
1322  Assert(found == IsUnderPostmaster);
1323  if (!found)
1325 
1326  /*
1327  * Initialize the SLRU storage for old committed serializable
1328  * transactions.
1329  */
1330  SerialInit();
1331 }
size_t Size
Definition: c.h:592
bool IsUnderPostmaster
Definition: globals.c:117
int MaxBackends
Definition: globals.c:143
@ HASH_ENTER
Definition: hsearch.h:114
#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_init(dlist_head *head)
Definition: ilist.h:314
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
static void dlist_node_init(dlist_node *node)
Definition: ilist.h:325
#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:204
static HTAB * PredicateLockHash
Definition: predicate.c:398
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:303
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:1399
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:582
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 PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:258
#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
#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
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 LastSxactCommitSeqNo
SerCommitSeqNo CanPartialClearThrough
SERIALIZABLEXACT * OldCommittedSxact
SerCommitSeqNo HavePartialClearedThrough
VirtualTransactionId vxid
dlist_head possibleUnsafeConflicts
SerCommitSeqNo prepareSeqNo
SerCommitSeqNo commitSeqNo
TransactionId finishedBefore
#define InvalidTransactionId
Definition: transam.h:31
int max_prepared_xacts
Definition: twophase.c:115

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

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

Definition at line 1988 of file predicate.c.

1989 {
1990  PREDICATELOCKTARGETTAG targettag;
1991  uint32 targettaghash;
1992  LWLock *partitionLock;
1993  PREDICATELOCKTARGET *target;
1994 
1996  relation->rd_locator.dbOid,
1997  relation->rd_id,
1998  blkno);
1999 
2000  targettaghash = PredicateLockTargetTagHashCode(&targettag);
2001  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2002  LWLockAcquire(partitionLock, LW_SHARED);
2003  target = (PREDICATELOCKTARGET *)
2005  &targettag, targettaghash,
2006  HASH_FIND, NULL);
2007  LWLockRelease(partitionLock);
2008 
2009  return (target != NULL);
2010 }
unsigned int uint32
Definition: c.h:493
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:968
Definition: lwlock.h:41

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

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

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

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

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

2580 {
2582 
2583  if (!SerializationNeededForRead(relation, snapshot))
2584  return;
2585 
2587  relation->rd_locator.dbOid,
2588  relation->rd_id,
2589  blkno);
2590  PredicateLockAcquire(&tag);
2591 }
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2497

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

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

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

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

Definition at line 3124 of file predicate.c.

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

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

2557 {
2559 
2560  if (!SerializationNeededForRead(relation, snapshot))
2561  return;
2562 
2564  relation->rd_locator.dbOid,
2565  relation->rd_id);
2566  PredicateLockAcquire(&tag);
2567 }

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

1338 {
1339  Size size = 0;
1340  long max_table_size;
1341 
1342  /* predicate lock target hash table */
1343  max_table_size = NPREDICATELOCKTARGETENTS();
1344  size = add_size(size, hash_estimate_size(max_table_size,
1345  sizeof(PREDICATELOCKTARGET)));
1346 
1347  /* predicate lock hash table */
1348  max_table_size *= 2;
1349  size = add_size(size, hash_estimate_size(max_table_size,
1350  sizeof(PREDICATELOCK)));
1351 
1352  /*
1353  * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
1354  * margin.
1355  */
1356  size = add_size(size, size / 10);
1357 
1358  /* transaction list */
1359  max_table_size = MaxBackends + max_prepared_xacts;
1360  max_table_size *= 10;
1362  size = add_size(size, mul_size((Size) max_table_size,
1363  sizeof(SERIALIZABLEXACT)));
1364 
1365  /* transaction xid table */
1366  size = add_size(size, hash_estimate_size(max_table_size,
1367  sizeof(SERIALIZABLEXID)));
1368 
1369  /* rw-conflict pool */
1370  max_table_size *= 5;
1372  size = add_size(size, mul_size((Size) max_table_size,
1374 
1375  /* Head for list of finished serializable transactions. */
1376  size = add_size(size, sizeof(dlist_head));
1377 
1378  /* Shared memory structures for SLRU tracking of old committed xids. */
1379  size = add_size(size, sizeof(SerialControlData));
1381 
1382  return size;
1383 }
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 2601 of file predicate.c.

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

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

4863 {
4864  SERIALIZABLEXID *sxid;
4865  SERIALIZABLEXIDTAG sxidtag;
4866 
4867  sxidtag.xid = xid;
4868 
4869  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4870  sxid = (SERIALIZABLEXID *)
4871  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4872  LWLockRelease(SerializableXactHashLock);
4873 
4874  /* xid will not be found if it wasn't a serializable transaction */
4875  if (sxid == NULL)
4876  return;
4877 
4878  /* Release its locks */
4879  MySerializableXact = sxid->myXact;
4880  MyXactDidWrite = true; /* conservatively assume that we wrote
4881  * something */
4882  ReleasePredicateLocks(isCommit, false);
4883 }
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3292

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

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

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

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

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

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

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

Referenced by SetTransactionSnapshot().

◆ ShareSerializableXact()

SerializableXactHandle ShareSerializableXact ( void  )

Definition at line 5026 of file predicate.c.

5027 {
5028  return MySerializableXact;
5029 }

References MySerializableXact.

Referenced by InitializeParallelDSM().

◆ TransferPredicateLocksToHeapRelation()

void TransferPredicateLocksToHeapRelation ( Relation  relation)

Definition at line 3103 of file predicate.c.

3104 {
3105  DropAllPredicateLocksFromTable(relation, true);
3106 }
static void DropAllPredicateLocksFromTable(Relation relation, bool transfer)
Definition: predicate.c:2917

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