PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 4780 of file predicate.c.

4781 {
4782  SERIALIZABLEXACT *sxact;
4783  TwoPhasePredicateRecord record;
4784  TwoPhasePredicateXactRecord *xactRecord;
4785  TwoPhasePredicateLockRecord *lockRecord;
4786  dlist_iter iter;
4787 
4788  sxact = MySerializableXact;
4789  xactRecord = &(record.data.xactRecord);
4790  lockRecord = &(record.data.lockRecord);
4791 
4793  return;
4794 
4795  /* Generate an xact record for our SERIALIZABLEXACT */
4797  xactRecord->xmin = MySerializableXact->xmin;
4798  xactRecord->flags = MySerializableXact->flags;
4799 
4800  /*
4801  * Note that we don't include the list of conflicts in our out in the
4802  * statefile, because new conflicts can be added even after the
4803  * transaction prepares. We'll just make a conservative assumption during
4804  * recovery instead.
4805  */
4806 
4808  &record, sizeof(record));
4809 
4810  /*
4811  * Generate a lock record for each lock.
4812  *
4813  * To do this, we need to walk the predicate lock list in our sxact rather
4814  * than using the local predicate lock table because the latter is not
4815  * guaranteed to be accurate.
4816  */
4817  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4818 
4819  /*
4820  * No need to take sxact->perXactPredicateListLock in parallel mode
4821  * because there cannot be any parallel workers running while we are
4822  * preparing a transaction.
4823  */
4825 
4826  dlist_foreach(iter, &sxact->predicateLocks)
4827  {
4828  PREDICATELOCK *predlock =
4829  dlist_container(PREDICATELOCK, xactLink, iter.cur);
4830 
4832  lockRecord->target = predlock->tag.myTarget->tag;
4833 
4835  &record, sizeof(record));
4836  }
4837 
4838  LWLockRelease(SerializablePredicateListLock);
4839 }
bool ParallelContextActive(void)
Definition: parallel.c:1020
#define Assert(condition)
Definition: c.h:837
#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
union TwoPhasePredicateRecord::@121 data
TwoPhasePredicateRecordType type
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 5045 of file predicate.c.

5046 {
5047 
5049 
5050  MySerializableXact = (SERIALIZABLEXACT *) handle;
5053 }
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1930

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

Referenced by ParallelWorkerMain().

◆ CheckForSerializableConflictIn()

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

Definition at line 4326 of file predicate.c.

4327 {
4328  PREDICATELOCKTARGETTAG targettag;
4329 
4330  if (!SerializationNeededForWrite(relation))
4331  return;
4332 
4333  /* Check if someone else has already decided that we need to die */
4335  ereport(ERROR,
4337  errmsg("could not serialize access due to read/write dependencies among transactions"),
4338  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4339  errhint("The transaction might succeed if retried.")));
4340 
4341  /*
4342  * We're doing a write which might cause rw-conflicts now or later.
4343  * Memorize that fact.
4344  */
4345  MyXactDidWrite = true;
4346 
4347  /*
4348  * It is important that we check for locks from the finest granularity to
4349  * the coarsest granularity, so that granularity promotion doesn't cause
4350  * us to miss a lock. The new (coarser) lock will be acquired before the
4351  * old (finer) locks are released.
4352  *
4353  * It is not possible to take and hold a lock across the checks for all
4354  * granularities because each target could be in a separate partition.
4355  */
4356  if (tid != NULL)
4357  {
4359  relation->rd_locator.dbOid,
4360  relation->rd_id,
4363  CheckTargetForConflictsIn(&targettag);
4364  }
4365 
4366  if (blkno != InvalidBlockNumber)
4367  {
4369  relation->rd_locator.dbOid,
4370  relation->rd_id,
4371  blkno);
4372  CheckTargetForConflictsIn(&targettag);
4373  }
4374 
4376  relation->rd_locator.dbOid,
4377  relation->rd_id);
4378  CheckTargetForConflictsIn(&targettag);
4379 }
#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:4156
#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 4013 of file predicate.c.

4014 {
4015  SERIALIZABLEXIDTAG sxidtag;
4016  SERIALIZABLEXID *sxid;
4017  SERIALIZABLEXACT *sxact;
4018 
4019  if (!SerializationNeededForRead(relation, snapshot))
4020  return;
4021 
4022  /* Check if someone else has already decided that we need to die */
4024  {
4025  ereport(ERROR,
4027  errmsg("could not serialize access due to read/write dependencies among transactions"),
4028  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4029  errhint("The transaction might succeed if retried.")));
4030  }
4032 
4034  return;
4035 
4036  /*
4037  * Find sxact or summarized info for the top level xid.
4038  */
4039  sxidtag.xid = xid;
4040  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4041  sxid = (SERIALIZABLEXID *)
4042  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4043  if (!sxid)
4044  {
4045  /*
4046  * Transaction not found in "normal" SSI structures. Check whether it
4047  * got pushed out to SLRU storage for "old committed" transactions.
4048  */
4049  SerCommitSeqNo conflictCommitSeqNo;
4050 
4051  conflictCommitSeqNo = SerialGetMinConflictCommitSeqNo(xid);
4052  if (conflictCommitSeqNo != 0)
4053  {
4054  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4056  || conflictCommitSeqNo
4058  ereport(ERROR,
4060  errmsg("could not serialize access due to read/write dependencies among transactions"),
4061  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4062  errhint("The transaction might succeed if retried.")));
4063 
4066  ereport(ERROR,
4068  errmsg("could not serialize access due to read/write dependencies among transactions"),
4069  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4070  errhint("The transaction might succeed if retried.")));
4071 
4073  }
4074 
4075  /* It's not serializable or otherwise not important. */
4076  LWLockRelease(SerializableXactHashLock);
4077  return;
4078  }
4079  sxact = sxid->myXact;
4080  Assert(TransactionIdEquals(sxact->topXid, xid));
4081  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4082  {
4083  /* Can't conflict with ourself or a transaction that will roll back. */
4084  LWLockRelease(SerializableXactHashLock);
4085  return;
4086  }
4087 
4088  /*
4089  * We have a conflict out to a transaction which has a conflict out to a
4090  * summarized transaction. That summarized transaction must have
4091  * committed first, and we can't tell when it committed in relation to our
4092  * snapshot acquisition, so something needs to be canceled.
4093  */
4094  if (SxactHasSummaryConflictOut(sxact))
4095  {
4096  if (!SxactIsPrepared(sxact))
4097  {
4098  sxact->flags |= SXACT_FLAG_DOOMED;
4099  LWLockRelease(SerializableXactHashLock);
4100  return;
4101  }
4102  else
4103  {
4104  LWLockRelease(SerializableXactHashLock);
4105  ereport(ERROR,
4107  errmsg("could not serialize access due to read/write dependencies among transactions"),
4108  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4109  errhint("The transaction might succeed if retried.")));
4110  }
4111  }
4112 
4113  /*
4114  * If this is a read-only transaction and the writing transaction has
4115  * committed, and it doesn't have a rw-conflict to a transaction which
4116  * committed before it, no conflict.
4117  */
4119  && SxactIsCommitted(sxact)
4120  && !SxactHasSummaryConflictOut(sxact)
4121  && (!SxactHasConflictOut(sxact)
4123  {
4124  /* Read-only transaction will appear to run first. No conflict. */
4125  LWLockRelease(SerializableXactHashLock);
4126  return;
4127  }
4128 
4129  if (!XidIsConcurrent(xid))
4130  {
4131  /* This write was already in our snapshot; no conflict. */
4132  LWLockRelease(SerializableXactHashLock);
4133  return;
4134  }
4135 
4137  {
4138  /* We don't want duplicate conflict records in the list. */
4139  LWLockRelease(SerializableXactHashLock);
4140  return;
4141  }
4142 
4143  /*
4144  * Flag the conflict. But first, if this conflict creates a dangerous
4145  * structure, ereport an error.
4146  */
4148  LWLockRelease(SerializableXactHashLock);
4149 }
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:4491
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:949
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:3962
#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::@120 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 3981 of file predicate.c.

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

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

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

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

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

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

1999 {
2000  PREDICATELOCKTARGETTAG targettag;
2001  uint32 targettaghash;
2002  LWLock *partitionLock;
2003  PREDICATELOCKTARGET *target;
2004 
2006  relation->rd_locator.dbOid,
2007  relation->rd_id,
2008  blkno);
2009 
2010  targettaghash = PredicateLockTargetTagHashCode(&targettag);
2011  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2012  LWLockAcquire(partitionLock, LW_SHARED);
2013  target = (PREDICATELOCKTARGET *)
2015  &targettag, targettaghash,
2016  HASH_FIND, NULL);
2017  LWLockRelease(partitionLock);
2018 
2019  return (target != NULL);
2020 }
unsigned int uint32
Definition: c.h:492
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 4693 of file predicate.c.

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

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

2590 {
2592 
2593  if (!SerializationNeededForRead(relation, snapshot))
2594  return;
2595 
2597  relation->rd_locator.dbOid,
2598  relation->rd_id,
2599  blkno);
2600  PredicateLockAcquire(&tag);
2601 }
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2507

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

Referenced by _bt_readpage(), _hash_first(), _hash_readnext(), collectMatchBitmap(), gistScanPage(), IndexOnlyNext(), moveRightIfItNeeded(), scanPendingInsert(), and startScanEntry().

◆ PredicateLockPageCombine()

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

Definition at line 3219 of file predicate.c.

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

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

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

Definition at line 3134 of file predicate.c.

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

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

2567 {
2569 
2570  if (!SerializationNeededForRead(relation, snapshot))
2571  return;
2572 
2574  relation->rd_locator.dbOid,
2575  relation->rd_id);
2576  PredicateLockAcquire(&tag);
2577 }

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

1146 {
1147  HASHCTL info;
1148  long max_table_size;
1149  Size requestSize;
1150  bool found;
1151 
1152 #ifndef EXEC_BACKEND
1154 #endif
1155 
1156  /*
1157  * Compute size of predicate lock target hashtable. Note these
1158  * calculations must agree with PredicateLockShmemSize!
1159  */
1160  max_table_size = NPREDICATELOCKTARGETENTS();
1161 
1162  /*
1163  * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1164  * per-predicate-lock-target information.
1165  */
1166  info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1167  info.entrysize = sizeof(PREDICATELOCKTARGET);
1169 
1170  PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1171  max_table_size,
1172  max_table_size,
1173  &info,
1174  HASH_ELEM | HASH_BLOBS |
1176 
1177  /*
1178  * Reserve a dummy entry in the hash table; we use it to make sure there's
1179  * always one entry available when we need to split or combine a page,
1180  * because running out of space there could mean aborting a
1181  * non-serializable transaction.
1182  */
1183  if (!IsUnderPostmaster)
1184  {
1186  HASH_ENTER, &found);
1187  Assert(!found);
1188  }
1189 
1190  /* Pre-calculate the hash and partition lock of the scratch entry */
1193 
1194  /*
1195  * Allocate hash table for PREDICATELOCK structs. This stores per
1196  * xact-lock-of-a-target information.
1197  */
1198  info.keysize = sizeof(PREDICATELOCKTAG);
1199  info.entrysize = sizeof(PREDICATELOCK);
1200  info.hash = predicatelock_hash;
1202 
1203  /* Assume an average of 2 xacts per target */
1204  max_table_size *= 2;
1205 
1206  PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1207  max_table_size,
1208  max_table_size,
1209  &info,
1212 
1213  /*
1214  * Compute size for serializable transaction hashtable. Note these
1215  * calculations must agree with PredicateLockShmemSize!
1216  */
1217  max_table_size = (MaxBackends + max_prepared_xacts);
1218 
1219  /*
1220  * Allocate a list to hold information on transactions participating in
1221  * predicate locking.
1222  *
1223  * Assume an average of 10 predicate locking transactions per backend.
1224  * This allows aggressive cleanup while detail is present before data must
1225  * be summarized for storage in SLRU and the "dummy" transaction.
1226  */
1227  max_table_size *= 10;
1228 
1229  PredXact = ShmemInitStruct("PredXactList",
1231  &found);
1232  Assert(found == IsUnderPostmaster);
1233  if (!found)
1234  {
1235  int i;
1236 
1245  requestSize = mul_size((Size) max_table_size,
1246  sizeof(SERIALIZABLEXACT));
1247  PredXact->element = ShmemAlloc(requestSize);
1248  /* Add all elements to available list, clean. */
1249  memset(PredXact->element, 0, requestSize);
1250  for (i = 0; i < max_table_size; i++)
1251  {
1255  }
1272  }
1273  /* This never changes, so let's keep a local copy. */
1275 
1276  /*
1277  * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1278  * information for serializable transactions which have accessed data.
1279  */
1280  info.keysize = sizeof(SERIALIZABLEXIDTAG);
1281  info.entrysize = sizeof(SERIALIZABLEXID);
1282 
1283  SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1284  max_table_size,
1285  max_table_size,
1286  &info,
1287  HASH_ELEM | HASH_BLOBS |
1288  HASH_FIXED_SIZE);
1289 
1290  /*
1291  * Allocate space for tracking rw-conflicts in lists attached to the
1292  * transactions.
1293  *
1294  * Assume an average of 5 conflicts per transaction. Calculations suggest
1295  * that this will prevent resource exhaustion in even the most pessimal
1296  * loads up to max_connections = 200 with all 200 connections pounding the
1297  * database with serializable transactions. Beyond that, there may be
1298  * occasional transactions canceled when trying to flag conflicts. That's
1299  * probably OK.
1300  */
1301  max_table_size *= 5;
1302 
1303  RWConflictPool = ShmemInitStruct("RWConflictPool",
1305  &found);
1306  Assert(found == IsUnderPostmaster);
1307  if (!found)
1308  {
1309  int i;
1310 
1312  requestSize = mul_size((Size) max_table_size,
1314  RWConflictPool->element = ShmemAlloc(requestSize);
1315  /* Add all elements to available list, clean. */
1316  memset(RWConflictPool->element, 0, requestSize);
1317  for (i = 0; i < max_table_size; i++)
1318  {
1321  }
1322  }
1323 
1324  /*
1325  * Create or attach to the header for the list of finished serializable
1326  * transactions.
1327  */
1329  ShmemInitStruct("FinishedSerializableTransactions",
1330  sizeof(dlist_head),
1331  &found);
1332  Assert(found == IsUnderPostmaster);
1333  if (!found)
1335 
1336  /*
1337  * Initialize the SLRU storage for old committed serializable
1338  * transactions.
1339  */
1340  SerialInit();
1341 }
size_t Size
Definition: c.h:584
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:1409
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:147
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:382
Size mul_size(Size s1, Size s2)
Definition: shmem.c:505
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:327
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 1347 of file predicate.c.

1348 {
1349  Size size = 0;
1350  long max_table_size;
1351 
1352  /* predicate lock target hash table */
1353  max_table_size = NPREDICATELOCKTARGETENTS();
1354  size = add_size(size, hash_estimate_size(max_table_size,
1355  sizeof(PREDICATELOCKTARGET)));
1356 
1357  /* predicate lock hash table */
1358  max_table_size *= 2;
1359  size = add_size(size, hash_estimate_size(max_table_size,
1360  sizeof(PREDICATELOCK)));
1361 
1362  /*
1363  * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
1364  * margin.
1365  */
1366  size = add_size(size, size / 10);
1367 
1368  /* transaction list */
1369  max_table_size = MaxBackends + max_prepared_xacts;
1370  max_table_size *= 10;
1372  size = add_size(size, mul_size((Size) max_table_size,
1373  sizeof(SERIALIZABLEXACT)));
1374 
1375  /* transaction xid table */
1376  size = add_size(size, hash_estimate_size(max_table_size,
1377  sizeof(SERIALIZABLEXID)));
1378 
1379  /* rw-conflict pool */
1380  max_table_size *= 5;
1382  size = add_size(size, mul_size((Size) max_table_size,
1384 
1385  /* Head for list of finished serializable transactions. */
1386  size = add_size(size, sizeof(dlist_head));
1387 
1388  /* Shared memory structures for SLRU tracking of old committed xids. */
1389  size = add_size(size, sizeof(SerialControlData));
1391 
1392  return size;
1393 }
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:488
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 2611 of file predicate.c.

2613 {
2615 
2616  if (!SerializationNeededForRead(relation, snapshot))
2617  return;
2618 
2619  /*
2620  * Return if this xact wrote it.
2621  */
2622  if (relation->rd_index == NULL)
2623  {
2624  /* If we wrote it; we already have a write lock. */
2625  if (TransactionIdIsCurrentTransactionId(tuple_xid))
2626  return;
2627  }
2628 
2629  /*
2630  * Do quick-but-not-definitive test for a relation lock first. This will
2631  * never cause a return when the relation is *not* locked, but will
2632  * occasionally let the check continue when there really *is* a relation
2633  * level lock.
2634  */
2636  relation->rd_locator.dbOid,
2637  relation->rd_id);
2638  if (PredicateLockExists(&tag))
2639  return;
2640 
2642  relation->rd_locator.dbOid,
2643  relation->rd_id,
2646  PredicateLockAcquire(&tag);
2647 }
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2035
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 4872 of file predicate.c.

4873 {
4874  SERIALIZABLEXID *sxid;
4875  SERIALIZABLEXIDTAG sxidtag;
4876 
4877  sxidtag.xid = xid;
4878 
4879  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4880  sxid = (SERIALIZABLEXID *)
4881  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4882  LWLockRelease(SerializableXactHashLock);
4883 
4884  /* xid will not be found if it wasn't a serializable transaction */
4885  if (sxid == NULL)
4886  return;
4887 
4888  /* Release its locks */
4889  MySerializableXact = sxid->myXact;
4890  MyXactDidWrite = true; /* conservatively assume that we wrote
4891  * something */
4892  ReleasePredicateLocks(isCommit, false);
4893 }
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3302

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

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

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

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

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

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

Referenced by SetTransactionSnapshot().

◆ ShareSerializableXact()

SerializableXactHandle ShareSerializableXact ( void  )

Definition at line 5036 of file predicate.c.

5037 {
5038  return MySerializableXact;
5039 }

References MySerializableXact.

Referenced by InitializeParallelDSM().

◆ TransferPredicateLocksToHeapRelation()

void TransferPredicateLocksToHeapRelation ( Relation  relation)

Definition at line 3113 of file predicate.c.

3114 {
3115  DropAllPredicateLocksFromTable(relation, true);
3116 }
static void DropAllPredicateLocksFromTable(Relation relation, bool transfer)
Definition: predicate.c:2927

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