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.

Macros

#define NUM_SERIAL_BUFFERS   16
 

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 insert_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
 

Macro Definition Documentation

◆ NUM_SERIAL_BUFFERS

#define NUM_SERIAL_BUFFERS   16

Definition at line 31 of file predicate.h.

Typedef Documentation

◆ SerializableXactHandle

typedef void* SerializableXactHandle

Definition at line 37 of file predicate.h.

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4927 of file predicate.c.

4928 {
4929  PREDICATELOCK *predlock;
4930  SERIALIZABLEXACT *sxact;
4931  TwoPhasePredicateRecord record;
4932  TwoPhasePredicateXactRecord *xactRecord;
4933  TwoPhasePredicateLockRecord *lockRecord;
4934 
4935  sxact = MySerializableXact;
4936  xactRecord = &(record.data.xactRecord);
4937  lockRecord = &(record.data.lockRecord);
4938 
4940  return;
4941 
4942  /* Generate an xact record for our SERIALIZABLEXACT */
4944  xactRecord->xmin = MySerializableXact->xmin;
4945  xactRecord->flags = MySerializableXact->flags;
4946 
4947  /*
4948  * Note that we don't include the list of conflicts in our out in the
4949  * statefile, because new conflicts can be added even after the
4950  * transaction prepares. We'll just make a conservative assumption during
4951  * recovery instead.
4952  */
4953 
4955  &record, sizeof(record));
4956 
4957  /*
4958  * Generate a lock record for each lock.
4959  *
4960  * To do this, we need to walk the predicate lock list in our sxact rather
4961  * than using the local predicate lock table because the latter is not
4962  * guaranteed to be accurate.
4963  */
4964  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4965 
4966  /*
4967  * No need to take sxact->perXactPredicateListLock in parallel mode
4968  * because there cannot be any parallel workers running while we are
4969  * preparing a transaction.
4970  */
4972 
4973  predlock = (PREDICATELOCK *)
4974  SHMQueueNext(&(sxact->predicateLocks),
4975  &(sxact->predicateLocks),
4976  offsetof(PREDICATELOCK, xactLink));
4977 
4978  while (predlock != NULL)
4979  {
4981  lockRecord->target = predlock->tag.myTarget->tag;
4982 
4984  &record, sizeof(record));
4985 
4986  predlock = (PREDICATELOCK *)
4987  SHMQueueNext(&(sxact->predicateLocks),
4988  &(predlock->xactLink),
4989  offsetof(PREDICATELOCK, xactLink));
4990  }
4991 
4992  LWLockRelease(SerializablePredicateListLock);
4993 }
bool ParallelContextActive(void)
Definition: parallel.c:990
#define offsetof(type, field)
Definition: c.h:727
#define IsParallelWorker()
Definition: parallel.h:61
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1196
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1800
@ LW_SHARED
Definition: lwlock.h:105
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:416
@ TWOPHASEPREDICATERECORD_XACT
@ TWOPHASEPREDICATERECORD_LOCK
#define InvalidSerializableXact
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGET * myTarget
PREDICATELOCKTARGETTAG tag
PREDICATELOCKTAG tag
PREDICATELOCKTARGETTAG target
TwoPhasePredicateRecordType type
union TwoPhasePredicateRecord::@116 data
TwoPhasePredicateLockRecord lockRecord
TwoPhasePredicateXactRecord xactRecord
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1259
#define TWOPHASE_RM_PREDICATELOCK_ID
Definition: twophase_rmgr.h:28

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

Referenced by PrepareTransaction().

◆ AttachSerializableXact()

void AttachSerializableXact ( SerializableXactHandle  handle)

Definition at line 5199 of file predicate.c.

5200 {
5201 
5203 
5204  MySerializableXact = (SERIALIZABLEXACT *) handle;
5207 }
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1924

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

Referenced by ParallelWorkerMain().

◆ CheckForSerializableConflictIn()

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

Definition at line 4448 of file predicate.c.

4449 {
4450  PREDICATELOCKTARGETTAG targettag;
4451 
4452  if (!SerializationNeededForWrite(relation))
4453  return;
4454 
4455  /* Check if someone else has already decided that we need to die */
4457  ereport(ERROR,
4459  errmsg("could not serialize access due to read/write dependencies among transactions"),
4460  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4461  errhint("The transaction might succeed if retried.")));
4462 
4463  /*
4464  * We're doing a write which might cause rw-conflicts now or later.
4465  * Memorize that fact.
4466  */
4467  MyXactDidWrite = true;
4468 
4469  /*
4470  * It is important that we check for locks from the finest granularity to
4471  * the coarsest granularity, so that granularity promotion doesn't cause
4472  * us to miss a lock. The new (coarser) lock will be acquired before the
4473  * old (finer) locks are released.
4474  *
4475  * It is not possible to take and hold a lock across the checks for all
4476  * granularities because each target could be in a separate partition.
4477  */
4478  if (tid != NULL)
4479  {
4481  relation->rd_node.dbNode,
4482  relation->rd_id,
4485  CheckTargetForConflictsIn(&targettag);
4486  }
4487 
4488  if (blkno != InvalidBlockNumber)
4489  {
4491  relation->rd_node.dbNode,
4492  relation->rd_id,
4493  blkno);
4494  CheckTargetForConflictsIn(&targettag);
4495  }
4496 
4498  relation->rd_node.dbNode,
4499  relation->rd_id);
4500  CheckTargetForConflictsIn(&targettag);
4501 }
#define InvalidBlockNumber
Definition: block.h:33
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1064
int errhint(const char *fmt,...)
Definition: elog.c:1151
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:79
static bool MyXactDidWrite
Definition: predicate.c:417
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:558
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4266
#define SxactIsDoomed(sxact)
Definition: predicate.c:275
#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:111
RelFileNode rd_node
Definition: rel.h:56

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

4124 {
4125  SERIALIZABLEXIDTAG sxidtag;
4126  SERIALIZABLEXID *sxid;
4127  SERIALIZABLEXACT *sxact;
4128 
4129  if (!SerializationNeededForRead(relation, snapshot))
4130  return;
4131 
4132  /* Check if someone else has already decided that we need to die */
4134  {
4135  ereport(ERROR,
4137  errmsg("could not serialize access due to read/write dependencies among transactions"),
4138  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4139  errhint("The transaction might succeed if retried.")));
4140  }
4142 
4144  return;
4145 
4146  /*
4147  * Find sxact or summarized info for the top level xid.
4148  */
4149  sxidtag.xid = xid;
4150  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4151  sxid = (SERIALIZABLEXID *)
4152  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4153  if (!sxid)
4154  {
4155  /*
4156  * Transaction not found in "normal" SSI structures. Check whether it
4157  * got pushed out to SLRU storage for "old committed" transactions.
4158  */
4159  SerCommitSeqNo conflictCommitSeqNo;
4160 
4161  conflictCommitSeqNo = SerialGetMinConflictCommitSeqNo(xid);
4162  if (conflictCommitSeqNo != 0)
4163  {
4164  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4166  || conflictCommitSeqNo
4168  ereport(ERROR,
4170  errmsg("could not serialize access due to read/write dependencies among transactions"),
4171  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4172  errhint("The transaction might succeed if retried.")));
4173 
4176  ereport(ERROR,
4178  errmsg("could not serialize access due to read/write dependencies among transactions"),
4179  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4180  errhint("The transaction might succeed if retried.")));
4181 
4183  }
4184 
4185  /* It's not serializable or otherwise not important. */
4186  LWLockRelease(SerializableXactHashLock);
4187  return;
4188  }
4189  sxact = sxid->myXact;
4190  Assert(TransactionIdEquals(sxact->topXid, xid));
4191  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4192  {
4193  /* Can't conflict with ourself or a transaction that will roll back. */
4194  LWLockRelease(SerializableXactHashLock);
4195  return;
4196  }
4197 
4198  /*
4199  * We have a conflict out to a transaction which has a conflict out to a
4200  * summarized transaction. That summarized transaction must have
4201  * committed first, and we can't tell when it committed in relation to our
4202  * snapshot acquisition, so something needs to be canceled.
4203  */
4204  if (SxactHasSummaryConflictOut(sxact))
4205  {
4206  if (!SxactIsPrepared(sxact))
4207  {
4208  sxact->flags |= SXACT_FLAG_DOOMED;
4209  LWLockRelease(SerializableXactHashLock);
4210  return;
4211  }
4212  else
4213  {
4214  LWLockRelease(SerializableXactHashLock);
4215  ereport(ERROR,
4217  errmsg("could not serialize access due to read/write dependencies among transactions"),
4218  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4219  errhint("The transaction might succeed if retried.")));
4220  }
4221  }
4222 
4223  /*
4224  * If this is a read-only transaction and the writing transaction has
4225  * committed, and it doesn't have a rw-conflict to a transaction which
4226  * committed before it, no conflict.
4227  */
4229  && SxactIsCommitted(sxact)
4230  && !SxactHasSummaryConflictOut(sxact)
4231  && (!SxactHasConflictOut(sxact)
4233  {
4234  /* Read-only transaction will appear to run first. No conflict. */
4235  LWLockRelease(SerializableXactHashLock);
4236  return;
4237  }
4238 
4239  if (!XidIsConcurrent(xid))
4240  {
4241  /* This write was already in our snapshot; no conflict. */
4242  LWLockRelease(SerializableXactHashLock);
4243  return;
4244  }
4245 
4247  {
4248  /* We don't want duplicate conflict records in the list. */
4249  LWLockRelease(SerializableXactHashLock);
4250  return;
4251  }
4252 
4253  /*
4254  * Flag the conflict. But first, if this conflict creates a dangerous
4255  * structure, ereport an error.
4256  */
4258  LWLockRelease(SerializableXactHashLock);
4259 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
@ HASH_FIND
Definition: hsearch.h:113
@ LW_EXCLUSIVE
Definition: lwlock.h:104
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:653
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:514
#define SxactIsCommitted(sxact)
Definition: predicate.c:272
#define SxactIsReadOnly(sxact)
Definition: predicate.c:276
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:277
#define SxactHasConflictOut(sxact)
Definition: predicate.c:284
#define SxactIsPrepared(sxact)
Definition: predicate.c:273
static HTAB * SerializableXidHash
Definition: predicate.c:391
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4623
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:977
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:4065
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:278
#define InvalidSerCommitSeqNo
#define SXACT_FLAG_DOOMED
uint64 SerCommitSeqNo
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
bool SHMQueueEmpty(const SHM_QUEUE *queue)
Definition: shmqueue.c:180
union SERIALIZABLEXACT::@115 SeqNo
SerCommitSeqNo lastCommitBeforeSnapshot
SerCommitSeqNo earliestOutConflictCommit
SERIALIZABLEXACT * myXact
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:428

References Assert(), SERIALIZABLEXACT::earliestOutConflictCommit, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, FlagRWConflict(), SERIALIZABLEXACT::flags, GetTopTransactionIdIfAny(), HASH_FIND, hash_search(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXID::myXact, RWConflictExists(), SERIALIZABLEXACT::SeqNo, SerialGetMinConflictCommitSeqNo(), SerializableXidHash, SerializationNeededForRead(), SHMQueueEmpty(), SXACT_FLAG_DOOMED, SXACT_FLAG_SUMMARY_CONFLICT_OUT, SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, SERIALIZABLEXACT::topXid, TransactionIdEquals, TransactionIdIsValid, SERIALIZABLEXIDTAG::xid, and XidIsConcurrent().

Referenced by HeapCheckForSerializableConflictOut().

◆ CheckForSerializableConflictOutNeeded()

bool CheckForSerializableConflictOutNeeded ( Relation  relation,
Snapshot  snapshot 
)

Definition at line 4091 of file predicate.c.

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

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

Referenced by HeapCheckForSerializableConflictOut().

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 1069 of file predicate.c.

1070 {
1071  int tailPage;
1072 
1073  LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
1074 
1075  /* Exit quickly if the SLRU is currently not in use. */
1076  if (serialControl->headPage < 0)
1077  {
1078  LWLockRelease(SerialSLRULock);
1079  return;
1080  }
1081 
1083  {
1084  /* We can truncate the SLRU up to the page containing tailXid */
1085  tailPage = SerialPage(serialControl->tailXid);
1086  }
1087  else
1088  {
1089  /*----------
1090  * The SLRU is no longer needed. Truncate to head before we set head
1091  * invalid.
1092  *
1093  * XXX: It's possible that the SLRU is not needed again until XID
1094  * wrap-around has happened, so that the segment containing headPage
1095  * that we leave behind will appear to be new again. In that case it
1096  * won't be removed until XID horizon advances enough to make it
1097  * current again.
1098  *
1099  * XXX: This should happen in vac_truncate_clog(), not in checkpoints.
1100  * Consider this scenario, starting from a system with no in-progress
1101  * transactions and VACUUM FREEZE having maximized oldestXact:
1102  * - Start a SERIALIZABLE transaction.
1103  * - Start, finish, and summarize a SERIALIZABLE transaction, creating
1104  * one SLRU page.
1105  * - Consume XIDs to reach xidStopLimit.
1106  * - Finish all transactions. Due to the long-running SERIALIZABLE
1107  * transaction, earlier checkpoints did not touch headPage. The
1108  * next checkpoint will change it, but that checkpoint happens after
1109  * the end of the scenario.
1110  * - VACUUM to advance XID limits.
1111  * - Consume ~2M XIDs, crossing the former xidWrapLimit.
1112  * - Start, finish, and summarize a SERIALIZABLE transaction.
1113  * SerialAdd() declines to create the targetPage, because headPage
1114  * is not regarded as in the past relative to that targetPage. The
1115  * transaction instigating the summarize fails in
1116  * SimpleLruReadPage().
1117  */
1118  tailPage = serialControl->headPage;
1119  serialControl->headPage = -1;
1120  }
1121 
1122  LWLockRelease(SerialSLRULock);
1123 
1124  /* Truncate away pages that are no longer required */
1125  SimpleLruTruncate(SerialSlruCtl, tailPage);
1126 
1127  /*
1128  * Write dirty SLRU pages to disk
1129  *
1130  * This is not actually necessary from a correctness point of view. We do
1131  * it merely as a debugging aid.
1132  *
1133  * We're doing this after the truncation to avoid writing pages right
1134  * before deleting the file in which they sit, which would be completely
1135  * pointless.
1136  */
1138 }
#define SerialPage(xid)
Definition: predicate.c:338
static SerialControl serialControl
Definition: predicate.c:349
#define SerialSlruCtl
Definition: predicate.c:321
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1156
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1226
TransactionId tailXid
Definition: predicate.c:344

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

Referenced by CheckPointGuts().

◆ CheckTableForSerializableConflictIn()

void CheckTableForSerializableConflictIn ( Relation  relation)

Definition at line 4531 of file predicate.c.

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

References Assert(), RelFileNode::dbNode, 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, offsetof, PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredXact, RelationData::rd_id, RelationData::rd_index, RelationData::rd_node, RWConflictExists(), SerializationNeededForWrite(), SHMQueueNext(), PredXactListData::SxactGlobalXmin, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, and TransactionIdIsValid.

Referenced by ExecuteTruncateGuts(), and heap_drop_with_catalog().

◆ GetSerializableTransactionSnapshot()

Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot)

Definition at line 1681 of file predicate.c.

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

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

1154 {
1155  HASHCTL info;
1156  long max_table_size;
1157  Size requestSize;
1158  bool found;
1159 
1160 #ifndef EXEC_BACKEND
1162 #endif
1163 
1164  /*
1165  * Compute size of predicate lock target hashtable. Note these
1166  * calculations must agree with PredicateLockShmemSize!
1167  */
1168  max_table_size = NPREDICATELOCKTARGETENTS();
1169 
1170  /*
1171  * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1172  * per-predicate-lock-target information.
1173  */
1174  info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1175  info.entrysize = sizeof(PREDICATELOCKTARGET);
1177 
1178  PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1179  max_table_size,
1180  max_table_size,
1181  &info,
1182  HASH_ELEM | HASH_BLOBS |
1184 
1185  /*
1186  * Reserve a dummy entry in the hash table; we use it to make sure there's
1187  * always one entry available when we need to split or combine a page,
1188  * because running out of space there could mean aborting a
1189  * non-serializable transaction.
1190  */
1191  if (!IsUnderPostmaster)
1192  {
1194  HASH_ENTER, &found);
1195  Assert(!found);
1196  }
1197 
1198  /* Pre-calculate the hash and partition lock of the scratch entry */
1201 
1202  /*
1203  * Allocate hash table for PREDICATELOCK structs. This stores per
1204  * xact-lock-of-a-target information.
1205  */
1206  info.keysize = sizeof(PREDICATELOCKTAG);
1207  info.entrysize = sizeof(PREDICATELOCK);
1208  info.hash = predicatelock_hash;
1210 
1211  /* Assume an average of 2 xacts per target */
1212  max_table_size *= 2;
1213 
1214  PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1215  max_table_size,
1216  max_table_size,
1217  &info,
1220 
1221  /*
1222  * Compute size for serializable transaction hashtable. Note these
1223  * calculations must agree with PredicateLockShmemSize!
1224  */
1225  max_table_size = (MaxBackends + max_prepared_xacts);
1226 
1227  /*
1228  * Allocate a list to hold information on transactions participating in
1229  * predicate locking.
1230  *
1231  * Assume an average of 10 predicate locking transactions per backend.
1232  * This allows aggressive cleanup while detail is present before data must
1233  * be summarized for storage in SLRU and the "dummy" transaction.
1234  */
1235  max_table_size *= 10;
1236 
1237  PredXact = ShmemInitStruct("PredXactList",
1239  &found);
1240  Assert(found == IsUnderPostmaster);
1241  if (!found)
1242  {
1243  int i;
1244 
1253  requestSize = mul_size((Size) max_table_size,
1255  PredXact->element = ShmemAlloc(requestSize);
1256  /* Add all elements to available list, clean. */
1257  memset(PredXact->element, 0, requestSize);
1258  for (i = 0; i < max_table_size; i++)
1259  {
1263  &(PredXact->element[i].link));
1264  }
1281  }
1282  /* This never changes, so let's keep a local copy. */
1284 
1285  /*
1286  * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1287  * information for serializable transactions which have accessed data.
1288  */
1289  info.keysize = sizeof(SERIALIZABLEXIDTAG);
1290  info.entrysize = sizeof(SERIALIZABLEXID);
1291 
1292  SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1293  max_table_size,
1294  max_table_size,
1295  &info,
1296  HASH_ELEM | HASH_BLOBS |
1297  HASH_FIXED_SIZE);
1298 
1299  /*
1300  * Allocate space for tracking rw-conflicts in lists attached to the
1301  * transactions.
1302  *
1303  * Assume an average of 5 conflicts per transaction. Calculations suggest
1304  * that this will prevent resource exhaustion in even the most pessimal
1305  * loads up to max_connections = 200 with all 200 connections pounding the
1306  * database with serializable transactions. Beyond that, there may be
1307  * occasional transactions canceled when trying to flag conflicts. That's
1308  * probably OK.
1309  */
1310  max_table_size *= 5;
1311 
1312  RWConflictPool = ShmemInitStruct("RWConflictPool",
1314  &found);
1315  Assert(found == IsUnderPostmaster);
1316  if (!found)
1317  {
1318  int i;
1319 
1321  requestSize = mul_size((Size) max_table_size,
1323  RWConflictPool->element = ShmemAlloc(requestSize);
1324  /* Add all elements to available list, clean. */
1325  memset(RWConflictPool->element, 0, requestSize);
1326  for (i = 0; i < max_table_size; i++)
1327  {
1330  }
1331  }
1332 
1333  /*
1334  * Create or attach to the header for the list of finished serializable
1335  * transactions.
1336  */
1338  ShmemInitStruct("FinishedSerializableTransactions",
1339  sizeof(SHM_QUEUE),
1340  &found);
1341  Assert(found == IsUnderPostmaster);
1342  if (!found)
1344 
1345  /*
1346  * Initialize the SLRU storage for old committed serializable
1347  * transactions.
1348  */
1349  SerialInit();
1350 }
size_t Size
Definition: c.h:540
bool IsUnderPostmaster
Definition: globals.c:113
int MaxBackends
Definition: globals.c:140
@ 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
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:79
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:734
@ LWTRANCHE_PER_XACT_PREDICATE_LIST
Definition: lwlock.h:192
static HTAB * PredicateLockHash
Definition: predicate.c:393
static SHM_QUEUE * FinishedSerializableTransactions
Definition: predicate.c:394
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:298
static LWLock * ScratchPartitionLock
Definition: predicate.c:403
static uint32 ScratchTargetTagHash
Definition: predicate.c:402
static uint32 predicatelock_hash(const void *key, Size keysize)
Definition: predicate.c:1418
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:580
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:357
static void SerialInit(void)
Definition: predicate.c:866
static const PREDICATELOCKTARGETTAG ScratchTargetTag
Definition: predicate.c:401
#define NPREDICATELOCKTARGETENTS()
Definition: predicate.c:259
static RWConflictPoolHeader RWConflictPool
Definition: predicate.c:385
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:253
#define RWConflictDataSize
#define FirstNormalSerCommitSeqNo
struct PREDICATELOCKTAG PREDICATELOCKTAG
#define PredXactListDataSize
#define RWConflictPoolHeaderDataSize
#define PredXactListElementDataSize
struct SERIALIZABLEXIDTAG SERIALIZABLEXIDTAG
struct PREDICATELOCKTARGET PREDICATELOCKTARGET
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
struct SERIALIZABLEXID SERIALIZABLEXID
#define SXACT_FLAG_COMMITTED
struct PREDICATELOCK PREDICATELOCK
#define INVALID_PGPROCNO
Definition: proc.h:83
void * ShmemAlloc(Size size)
Definition: shmem.c:161
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:341
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
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
PredXactListElement element
SerCommitSeqNo LastSxactCommitSeqNo
SerCommitSeqNo CanPartialClearThrough
SERIALIZABLEXACT * OldCommittedSxact
SerCommitSeqNo HavePartialClearedThrough
SHM_QUEUE possibleUnsafeConflicts
VirtualTransactionId vxid
SerCommitSeqNo prepareSeqNo
SerCommitSeqNo commitSeqNo
TransactionId finishedBefore
#define InvalidTransactionId
Definition: transam.h:31
int max_prepared_xacts
Definition: twophase.c:117

References PredXactListData::activeList, Assert(), PredXactListData::availableList, RWConflictPoolHeaderData::availableList, PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, CreatePredXact(), PredXactListData::element, RWConflictPoolHeaderData::element, HASHCTL::entrysize, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, FirstNormalSerCommitSeqNo, SERIALIZABLEXACT::flags, HASHCTL::hash, HASH_BLOBS, HASH_ELEM, HASH_ENTER, HASH_FIXED_SIZE, HASH_FUNCTION, HASH_PARTITION, hash_search(), PredXactListData::HavePartialClearedThrough, i, SERIALIZABLEXACT::inConflicts, INVALID_PGPROCNO, InvalidTransactionId, IsUnderPostmaster, HASHCTL::keysize, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, PredXactListElementData::link, LWLockInitialize(), LWTRANCHE_PER_XACT_PREDICATE_LIST, max_prepared_xacts, MaxBackends, mul_size(), NPREDICATELOCKTARGETENTS, HASHCTL::num_partitions, NUM_PREDICATELOCK_PARTITIONS, OldCommittedSxact, PredXactListData::OldCommittedSxact, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::perXactPredicateListLock, SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, predicatelock_hash(), PredicateLockHash, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetHash, PredicateLockTargetTagHashCode, PredXact, PredXactListDataSize, PredXactListElementDataSize, SERIALIZABLEXACT::prepareSeqNo, RWConflictDataSize, RWConflictPool, RWConflictPoolHeaderDataSize, ScratchPartitionLock, ScratchTargetTag, ScratchTargetTagHash, SERIALIZABLEXACT::SeqNo, SerialInit(), SerializableXidHash, SetInvalidVirtualTransactionId, ShmemAlloc(), ShmemInitHash(), ShmemInitStruct(), SHMQueueInit(), SHMQueueInsertBefore(), PredXactListElementData::sxact, SXACT_FLAG_COMMITTED, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SERIALIZABLEXACT::topXid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, and SERIALIZABLEXACT::xmin.

Referenced by CreateSharedMemoryAndSemaphores().

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

Definition at line 1992 of file predicate.c.

1993 {
1994  PREDICATELOCKTARGETTAG targettag;
1995  uint32 targettaghash;
1996  LWLock *partitionLock;
1997  PREDICATELOCKTARGET *target;
1998 
2000  relation->rd_node.dbNode,
2001  relation->rd_id,
2002  blkno);
2003 
2004  targettaghash = PredicateLockTargetTagHashCode(&targettag);
2005  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2006  LWLockAcquire(partitionLock, LW_SHARED);
2007  target = (PREDICATELOCKTARGET *)
2009  &targettag, targettaghash,
2010  HASH_FIND, NULL);
2011  LWLockRelease(partitionLock);
2012 
2013  return (target != NULL);
2014 }
unsigned int uint32
Definition: c.h:441
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:967
Definition: lwlock.h:32

References RelFileNode::dbNode, HASH_FIND, hash_search_with_hash_value(), LW_SHARED, LWLockAcquire(), LWLockRelease(), PredicateLockHashPartitionLock, PredicateLockTargetHash, PredicateLockTargetTagHashCode, RelationData::rd_id, RelationData::rd_node, and SET_PREDICATELOCKTARGETTAG_PAGE.

◆ PostPrepare_PredicateLocks()

void PostPrepare_PredicateLocks ( TransactionId  xid)

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4833 of file predicate.c.

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

References Assert(), ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, InvalidSerializableXact, IsolationIsSerializable, PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, offsetof, PredXact, SERIALIZABLEXACT::prepareSeqNo, SHMQueueNext(), 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 5053 of file predicate.c.

5055 {
5056  TwoPhasePredicateRecord *record;
5057 
5058  Assert(len == sizeof(TwoPhasePredicateRecord));
5059 
5060  record = (TwoPhasePredicateRecord *) recdata;
5061 
5062  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
5063  (record->type == TWOPHASEPREDICATERECORD_LOCK));
5064 
5065  if (record->type == TWOPHASEPREDICATERECORD_XACT)
5066  {
5067  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
5068  TwoPhasePredicateXactRecord *xactRecord;
5069  SERIALIZABLEXACT *sxact;
5070  SERIALIZABLEXID *sxid;
5071  SERIALIZABLEXIDTAG sxidtag;
5072  bool found;
5073 
5074  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
5075 
5076  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
5077  sxact = CreatePredXact();
5078  if (!sxact)
5079  ereport(ERROR,
5080  (errcode(ERRCODE_OUT_OF_MEMORY),
5081  errmsg("out of shared memory")));
5082 
5083  /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
5084  sxact->vxid.backendId = InvalidBackendId;
5086  sxact->pid = 0;
5087  sxact->pgprocno = INVALID_PGPROCNO;
5088 
5089  /* a prepared xact hasn't committed yet */
5093 
5095 
5096  /*
5097  * Don't need to track this; no transactions running at the time the
5098  * recovered xact started are still active, except possibly other
5099  * prepared xacts and we don't care whether those are RO_SAFE or not.
5100  */
5102 
5103  SHMQueueInit(&(sxact->predicateLocks));
5104  SHMQueueElemInit(&(sxact->finishedLink));
5105 
5106  sxact->topXid = xid;
5107  sxact->xmin = xactRecord->xmin;
5108  sxact->flags = xactRecord->flags;
5109  Assert(SxactIsPrepared(sxact));
5110  if (!SxactIsReadOnly(sxact))
5111  {
5115  }
5116 
5117  /*
5118  * We don't know whether the transaction had any conflicts or not, so
5119  * we'll conservatively assume that it had both a conflict in and a
5120  * conflict out, and represent that with the summary conflict flags.
5121  */
5122  SHMQueueInit(&(sxact->outConflicts));
5123  SHMQueueInit(&(sxact->inConflicts));
5126 
5127  /* Register the transaction's xid */
5128  sxidtag.xid = xid;
5130  &sxidtag,
5131  HASH_ENTER, &found);
5132  Assert(sxid != NULL);
5133  Assert(!found);
5134  sxid->myXact = (SERIALIZABLEXACT *) sxact;
5135 
5136  /*
5137  * Update global xmin. Note that this is a special case compared to
5138  * registering a normal transaction, because the global xmin might go
5139  * backwards. That's OK, because until recovery is over we're not
5140  * going to complete any transactions or create any non-prepared
5141  * transactions, so there's no danger of throwing away.
5142  */
5145  {
5146  PredXact->SxactGlobalXmin = sxact->xmin;
5148  SerialSetActiveSerXmin(sxact->xmin);
5149  }
5150  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
5151  {
5154  }
5155 
5156  LWLockRelease(SerializableXactHashLock);
5157  }
5158  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
5159  {
5160  /* Lock record. Recreate the PREDICATELOCK */
5161  TwoPhasePredicateLockRecord *lockRecord;
5162  SERIALIZABLEXID *sxid;
5163  SERIALIZABLEXACT *sxact;
5164  SERIALIZABLEXIDTAG sxidtag;
5165  uint32 targettaghash;
5166 
5167  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
5168  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
5169 
5170  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
5171  sxidtag.xid = xid;
5172  sxid = (SERIALIZABLEXID *)
5173  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
5174  LWLockRelease(SerializableXactHashLock);
5175 
5176  Assert(sxid != NULL);
5177  sxact = sxid->myXact;
5178  Assert(sxact != InvalidSerializableXact);
5179 
5180  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5181  }
5182 }
#define InvalidBackendId
Definition: backendid.h:23
uint32 LocalTransactionId
Definition: c.h:589
const void size_t len
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2447
static void SerialSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:1018
#define SXACT_FLAG_SUMMARY_CONFLICT_IN
#define RecoverySerCommitSeqNo
void SHMQueueElemInit(SHM_QUEUE *queue)
Definition: shmqueue.c:57
LocalTransactionId localTransactionId
Definition: lock.h:67
BackendId backendId
Definition: lock.h:66
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334

References Assert(), VirtualTransactionId::backendId, SERIALIZABLEXACT::commitSeqNo, CreatePredicateLock(), CreatePredXact(), TwoPhasePredicateRecord::data, ereport, errcode(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, SERIALIZABLEXACT::flags, TwoPhasePredicateXactRecord::flags, HASH_ENTER, HASH_FIND, hash_search(), SERIALIZABLEXACT::inConflicts, INVALID_PGPROCNO, InvalidBackendId, InvalidSerCommitSeqNo, InvalidSerializableXact, InvalidTransactionId, SERIALIZABLEXACT::lastCommitBeforeSnapshot, len, VirtualTransactionId::localTransactionId, TwoPhasePredicateRecord::lockRecord, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_prepared_xacts, MaxBackends, SERIALIZABLEXID::myXact, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, PredXact, SERIALIZABLEXACT::prepareSeqNo, RecoverySerCommitSeqNo, SERIALIZABLEXACT::SeqNo, SerializableXidHash, SerialSetActiveSerXmin(), SHMQueueElemInit(), SHMQueueInit(), SXACT_FLAG_SUMMARY_CONFLICT_IN, SXACT_FLAG_SUMMARY_CONFLICT_OUT, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactIsPrepared, SxactIsReadOnly, TwoPhasePredicateLockRecord::target, SERIALIZABLEXACT::topXid, TransactionIdEquals, TransactionIdFollows(), TransactionIdIsValid, TWOPHASEPREDICATERECORD_LOCK, TWOPHASEPREDICATERECORD_XACT, TwoPhasePredicateRecord::type, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, TwoPhasePredicateRecord::xactRecord, SERIALIZABLEXIDTAG::xid, SERIALIZABLEXACT::xmin, and TwoPhasePredicateXactRecord::xmin.

◆ PredicateLockPage()

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

Definition at line 2594 of file predicate.c.

2595 {
2597 
2598  if (!SerializationNeededForRead(relation, snapshot))
2599  return;
2600 
2602  relation->rd_node.dbNode,
2603  relation->rd_id,
2604  blkno);
2605  PredicateLockAcquire(&tag);
2606 }
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2512

References RelFileNode::dbNode, PredicateLockAcquire(), RelationData::rd_id, RelationData::rd_node, 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 3254 of file predicate.c.

3256 {
3257  /*
3258  * Page combines differ from page splits in that we ought to be able to
3259  * remove the locks on the old page after transferring them to the new
3260  * page, instead of duplicating them. However, because we can't edit other
3261  * backends' local lock tables, removing the old lock would leave them
3262  * with an entry in their LocalPredicateLockHash for a lock they're not
3263  * holding, which isn't acceptable. So we wind up having to do the same
3264  * work as a page split, acquiring a lock on the new page and keeping the
3265  * old page locked too. That can lead to some false positives, but should
3266  * be rare in practice.
3267  */
3268  PredicateLockPageSplit(relation, oldblkno, newblkno);
3269 }
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3169

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

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

Definition at line 3169 of file predicate.c.

3171 {
3172  PREDICATELOCKTARGETTAG oldtargettag;
3173  PREDICATELOCKTARGETTAG newtargettag;
3174  bool success;
3175 
3176  /*
3177  * Bail out quickly if there are no serializable transactions running.
3178  *
3179  * It's safe to do this check without taking any additional locks. Even if
3180  * a serializable transaction starts concurrently, we know it can't take
3181  * any SIREAD locks on the page being split because the caller is holding
3182  * the associated buffer page lock. Memory reordering isn't an issue; the
3183  * memory barrier in the LWLock acquisition guarantees that this read
3184  * occurs while the buffer page lock is held.
3185  */
3187  return;
3188 
3189  if (!PredicateLockingNeededForRelation(relation))
3190  return;
3191 
3192  Assert(oldblkno != newblkno);
3193  Assert(BlockNumberIsValid(oldblkno));
3194  Assert(BlockNumberIsValid(newblkno));
3195 
3196  SET_PREDICATELOCKTARGETTAG_PAGE(oldtargettag,
3197  relation->rd_node.dbNode,
3198  relation->rd_id,
3199  oldblkno);
3200  SET_PREDICATELOCKTARGETTAG_PAGE(newtargettag,
3201  relation->rd_node.dbNode,
3202  relation->rd_id,
3203  newblkno);
3204 
3205  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
3206 
3207  /*
3208  * Try copying the locks over to the new page's tag, creating it if
3209  * necessary.
3210  */
3212  newtargettag,
3213  false);
3214 
3215  if (!success)
3216  {
3217  /*
3218  * No more predicate lock entries are available. Failure isn't an
3219  * option here, so promote the page lock to a relation lock.
3220  */
3221 
3222  /* Get the parent relation lock's lock tag */
3223  success = GetParentPredicateLockTag(&oldtargettag,
3224  &newtargettag);
3225  Assert(success);
3226 
3227  /*
3228  * Move the locks to the parent. This shouldn't fail.
3229  *
3230  * Note that here we are removing locks held by other backends,
3231  * leading to a possible inconsistency in their local lock hash table.
3232  * This is OK because we're replacing it with a lock that covers the
3233  * old one.
3234  */
3236  newtargettag,
3237  true);
3238  Assert(success);
3239  }
3240 
3241  LWLockRelease(SerializablePredicateListLock);
3242 }
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
static bool success
Definition: initdb.c:169
static bool PredicateLockingNeededForRelation(Relation relation)
Definition: predicate.c:495
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:2056
static bool TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag, PREDICATELOCKTARGETTAG newtargettag, bool removeOld)
Definition: predicate.c:2735

References Assert(), BlockNumberIsValid, RelFileNode::dbNode, GetParentPredicateLockTag(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PredicateLockingNeededForRelation(), PredXact, RelationData::rd_id, RelationData::rd_node, SET_PREDICATELOCKTARGETTAG_PAGE, success, PredXactListData::SxactGlobalXmin, TransactionIdIsValid, and TransferPredicateLocksToNewTarget().

Referenced by _bt_insertonpg(), _hash_splitbucket(), createPostingTree(), ginPlaceToPage(), gistplacetopage(), and PredicateLockPageCombine().

◆ PredicateLockRelation()

void PredicateLockRelation ( Relation  relation,
Snapshot  snapshot 
)

Definition at line 2571 of file predicate.c.

2572 {
2574 
2575  if (!SerializationNeededForRead(relation, snapshot))
2576  return;
2577 
2579  relation->rd_node.dbNode,
2580  relation->rd_id);
2581  PredicateLockAcquire(&tag);
2582 }

References RelFileNode::dbNode, PredicateLockAcquire(), RelationData::rd_id, RelationData::rd_node, SerializationNeededForRead(), and SET_PREDICATELOCKTARGETTAG_RELATION.

Referenced by _bt_endpoint(), _bt_first(), heap_beginscan(), and index_beginscan_internal().

◆ PredicateLockShmemSize()

Size PredicateLockShmemSize ( void  )

Definition at line 1356 of file predicate.c.

1357 {
1358  Size size = 0;
1359  long max_table_size;
1360 
1361  /* predicate lock target hash table */
1362  max_table_size = NPREDICATELOCKTARGETENTS();
1363  size = add_size(size, hash_estimate_size(max_table_size,
1364  sizeof(PREDICATELOCKTARGET)));
1365 
1366  /* predicate lock hash table */
1367  max_table_size *= 2;
1368  size = add_size(size, hash_estimate_size(max_table_size,
1369  sizeof(PREDICATELOCK)));
1370 
1371  /*
1372  * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
1373  * margin.
1374  */
1375  size = add_size(size, size / 10);
1376 
1377  /* transaction list */
1378  max_table_size = MaxBackends + max_prepared_xacts;
1379  max_table_size *= 10;
1380  size = add_size(size, PredXactListDataSize);
1381  size = add_size(size, mul_size((Size) max_table_size,
1383 
1384  /* transaction xid table */
1385  size = add_size(size, hash_estimate_size(max_table_size,
1386  sizeof(SERIALIZABLEXID)));
1387 
1388  /* rw-conflict pool */
1389  max_table_size *= 5;
1390  size = add_size(size, RWConflictPoolHeaderDataSize);
1391  size = add_size(size, mul_size((Size) max_table_size,
1393 
1394  /* Head for list of finished serializable transactions. */
1395  size = add_size(size, sizeof(SHM_QUEUE));
1396 
1397  /* Shared memory structures for SLRU tracking of old committed xids. */
1398  size = add_size(size, sizeof(SerialControlData));
1400 
1401  return size;
1402 }
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:780
#define NUM_SERIAL_BUFFERS
Definition: predicate.h:31
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:156

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

Referenced by CalculateShmemSize().

◆ PredicateLockTID()

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

Definition at line 2616 of file predicate.c.

2618 {
2620 
2621  if (!SerializationNeededForRead(relation, snapshot))
2622  return;
2623 
2624  /*
2625  * Return if this xact wrote it.
2626  */
2627  if (relation->rd_index == NULL)
2628  {
2629  /* If we wrote it; we already have a write lock. */
2630  if (TransactionIdIsCurrentTransactionId(tuple_xid))
2631  return;
2632  }
2633 
2634  /*
2635  * Do quick-but-not-definitive test for a relation lock first. This will
2636  * never cause a return when the relation is *not* locked, but will
2637  * occasionally let the check continue when there really *is* a relation
2638  * level lock.
2639  */
2641  relation->rd_node.dbNode,
2642  relation->rd_id);
2643  if (PredicateLockExists(&tag))
2644  return;
2645 
2647  relation->rd_node.dbNode,
2648  relation->rd_id,
2651  PredicateLockAcquire(&tag);
2652 }
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2029
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:922

References RelFileNode::dbNode, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, PredicateLockAcquire(), PredicateLockExists(), RelationData::rd_id, RelationData::rd_index, RelationData::rd_node, 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 5026 of file predicate.c.

5027 {
5028  SERIALIZABLEXID *sxid;
5029  SERIALIZABLEXIDTAG sxidtag;
5030 
5031  sxidtag.xid = xid;
5032 
5033  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
5034  sxid = (SERIALIZABLEXID *)
5035  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
5036  LWLockRelease(SerializableXactHashLock);
5037 
5038  /* xid will not be found if it wasn't a serializable transaction */
5039  if (sxid == NULL)
5040  return;
5041 
5042  /* Release its locks */
5043  MySerializableXact = sxid->myXact;
5044  MyXactDidWrite = true; /* conservatively assume that we wrote
5045  * something */
5046  ReleasePredicateLocks(isCommit, false);
5047 }
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3334

References HASH_FIND, hash_search(), LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXID::myXact, MyXactDidWrite, ReleasePredicateLocks(), SerializableXidHash, and SERIALIZABLEXIDTAG::xid.

Referenced by FinishPreparedTransaction().

◆ RegisterPredicateLockingXid()

void RegisterPredicateLockingXid ( TransactionId  xid)

Definition at line 1943 of file predicate.c.

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

References Assert(), HASH_ENTER, hash_search(), InvalidSerializableXact, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXID::myXact, SerializableXidHash, SERIALIZABLEXACT::topXid, TransactionIdIsValid, and SERIALIZABLEXIDTAG::xid.

Referenced by AssignTransactionId().

◆ ReleasePredicateLocks()

void ReleasePredicateLocks ( bool  isCommit,
bool  isReadOnlySafe 
)

Definition at line 3334 of file predicate.c.

3335 {
3336  bool needToClear;
3337  RWConflict conflict,
3338  nextConflict,
3339  possibleUnsafeConflict;
3340  SERIALIZABLEXACT *roXact;
3341 
3342  /*
3343  * We can't trust XactReadOnly here, because a transaction which started
3344  * as READ WRITE can show as READ ONLY later, e.g., within
3345  * subtransactions. We want to flag a transaction as READ ONLY if it
3346  * commits without writing so that de facto READ ONLY transactions get the
3347  * benefit of some RO optimizations, so we will use this local variable to
3348  * get some cleanup logic right which is based on whether the transaction
3349  * was declared READ ONLY at the top level.
3350  */
3351  bool topLevelIsDeclaredReadOnly;
3352 
3353  /* We can't be both committing and releasing early due to RO_SAFE. */
3354  Assert(!(isCommit && isReadOnlySafe));
3355 
3356  /* Are we at the end of a transaction, that is, a commit or abort? */
3357  if (!isReadOnlySafe)
3358  {
3359  /*
3360  * Parallel workers mustn't release predicate locks at the end of
3361  * their transaction. The leader will do that at the end of its
3362  * transaction.
3363  */
3364  if (IsParallelWorker())
3365  {
3367  return;
3368  }
3369 
3370  /*
3371  * By the time the leader in a parallel query reaches end of
3372  * transaction, it has waited for all workers to exit.
3373  */
3375 
3376  /*
3377  * If the leader in a parallel query earlier stashed a partially
3378  * released SERIALIZABLEXACT for final clean-up at end of transaction
3379  * (because workers might still have been accessing it), then it's
3380  * time to restore it.
3381  */
3383  {
3388  }
3389  }
3390 
3392  {
3393  Assert(LocalPredicateLockHash == NULL);
3394  return;
3395  }
3396 
3397  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3398 
3399  /*
3400  * If the transaction is committing, but it has been partially released
3401  * already, then treat this as a roll back. It was marked as rolled back.
3402  */
3404  isCommit = false;
3405 
3406  /*
3407  * If we're called in the middle of a transaction because we discovered
3408  * that the SXACT_FLAG_RO_SAFE flag was set, then we'll partially release
3409  * it (that is, release the predicate locks and conflicts, but not the
3410  * SERIALIZABLEXACT itself) if we're the first backend to have noticed.
3411  */
3412  if (isReadOnlySafe && IsInParallelMode())
3413  {
3414  /*
3415  * The leader needs to stash a pointer to it, so that it can
3416  * completely release it at end-of-transaction.
3417  */
3418  if (!IsParallelWorker())
3420 
3421  /*
3422  * The first backend to reach this condition will partially release
3423  * the SERIALIZABLEXACT. All others will just clear their
3424  * backend-local state so that they stop doing SSI checks for the rest
3425  * of the transaction.
3426  */
3428  {
3429  LWLockRelease(SerializableXactHashLock);
3431  return;
3432  }
3433  else
3434  {
3436  /* ... and proceed to perform the partial release below. */
3437  }
3438  }
3439  Assert(!isCommit || SxactIsPrepared(MySerializableXact));
3440  Assert(!isCommit || !SxactIsDoomed(MySerializableXact));
3444 
3445  /* may not be serializable during COMMIT/ROLLBACK PREPARED */
3447 
3448  /* We'd better not already be on the cleanup list. */
3450 
3451  topLevelIsDeclaredReadOnly = SxactIsReadOnly(MySerializableXact);
3452 
3453  /*
3454  * We don't hold XidGenLock lock here, assuming that TransactionId is
3455  * atomic!
3456  *
3457  * If this value is changing, we don't care that much whether we get the
3458  * old or new value -- it is just used to determine how far
3459  * SxactGlobalXmin must advance before this transaction can be fully
3460  * cleaned up. The worst that could happen is we wait for one more
3461  * transaction to complete before freeing some RAM; correctness of visible
3462  * behavior is not affected.
3463  */
3465 
3466  /*
3467  * If it's not a commit it's either a rollback or a read-only transaction
3468  * flagged SXACT_FLAG_RO_SAFE, and we can clear our locks immediately.
3469  */
3470  if (isCommit)
3471  {
3474  /* Recognize implicit read-only transaction (commit without write). */
3475  if (!MyXactDidWrite)
3477  }
3478  else
3479  {
3480  /*
3481  * The DOOMED flag indicates that we intend to roll back this
3482  * transaction and so it should not cause serialization failures for
3483  * other transactions that conflict with it. Note that this flag might
3484  * already be set, if another backend marked this transaction for
3485  * abort.
3486  *
3487  * The ROLLED_BACK flag further indicates that ReleasePredicateLocks
3488  * has been called, and so the SerializableXact is eligible for
3489  * cleanup. This means it should not be considered when calculating
3490  * SxactGlobalXmin.
3491  */
3494 
3495  /*
3496  * If the transaction was previously prepared, but is now failing due
3497  * to a ROLLBACK PREPARED or (hopefully very rare) error after the
3498  * prepare, clear the prepared flag. This simplifies conflict
3499  * checking.
3500  */
3502  }
3503 
3504  if (!topLevelIsDeclaredReadOnly)
3505  {
3507  if (--(PredXact->WritableSxactCount) == 0)
3508  {
3509  /*
3510  * Release predicate locks and rw-conflicts in for all committed
3511  * transactions. There are no longer any transactions which might
3512  * conflict with the locks and no chance for new transactions to
3513  * overlap. Similarly, existing conflicts in can't cause pivots,
3514  * and any conflicts in which could have completed a dangerous
3515  * structure would already have caused a rollback, so any
3516  * remaining ones must be benign.
3517  */
3519  }
3520  }
3521  else
3522  {
3523  /*
3524  * Read-only transactions: clear the list of transactions that might
3525  * make us unsafe. Note that we use 'inLink' for the iteration as
3526  * opposed to 'outLink' for the r/w xacts.
3527  */
3528  possibleUnsafeConflict = (RWConflict)
3531  offsetof(RWConflictData, inLink));
3532  while (possibleUnsafeConflict)
3533  {
3534  nextConflict = (RWConflict)
3536  &possibleUnsafeConflict->inLink,
3537  offsetof(RWConflictData, inLink));
3538 
3539  Assert(!SxactIsReadOnly(possibleUnsafeConflict->sxactOut));
3540  Assert(MySerializableXact == possibleUnsafeConflict->sxactIn);
3541 
3542  ReleaseRWConflict(possibleUnsafeConflict);
3543 
3544  possibleUnsafeConflict = nextConflict;
3545  }
3546  }
3547 
3548  /* Check for conflict out to old committed transactions. */
3549  if (isCommit
3552  {
3553  /*
3554  * we don't know which old committed transaction we conflicted with,
3555  * so be conservative and use FirstNormalSerCommitSeqNo here
3556  */
3560  }
3561 
3562  /*
3563  * Release all outConflicts to committed transactions. If we're rolling
3564  * back clear them all. Set SXACT_FLAG_CONFLICT_OUT if any point to
3565  * previously committed transactions.
3566  */
3567  conflict = (RWConflict)
3570  offsetof(RWConflictData, outLink));
3571  while (conflict)
3572  {
3573  nextConflict = (RWConflict)
3575  &conflict->outLink,
3576  offsetof(RWConflictData, outLink));
3577 
3578  if (isCommit
3580  && SxactIsCommitted(conflict->sxactIn))
3581  {
3586  }
3587 
3588  if (!isCommit
3589  || SxactIsCommitted(conflict->sxactIn)
3591  ReleaseRWConflict(conflict);
3592 
3593  conflict = nextConflict;
3594  }
3595 
3596  /*
3597  * Release all inConflicts from committed and read-only transactions. If
3598  * we're rolling back, clear them all.
3599  */
3600  conflict = (RWConflict)
3603  offsetof(RWConflictData, inLink));
3604  while (conflict)
3605  {
3606  nextConflict = (RWConflict)
3608  &conflict->inLink,
3609  offsetof(RWConflictData, inLink));
3610 
3611  if (!isCommit
3612  || SxactIsCommitted(conflict->sxactOut)
3613  || SxactIsReadOnly(conflict->sxactOut))
3614  ReleaseRWConflict(conflict);
3615 
3616  conflict = nextConflict;
3617  }
3618 
3619  if (!topLevelIsDeclaredReadOnly)
3620  {
3621  /*
3622  * Remove ourselves from the list of possible conflicts for concurrent
3623  * READ ONLY transactions, flagging them as unsafe if we have a
3624  * conflict out. If any are waiting DEFERRABLE transactions, wake them
3625  * up if they are known safe or known unsafe.
3626  */
3627  possibleUnsafeConflict = (RWConflict)
3630  offsetof(RWConflictData, outLink));
3631  while (possibleUnsafeConflict)
3632  {
3633  nextConflict = (RWConflict)
3635  &possibleUnsafeConflict->outLink,
3636  offsetof(RWConflictData, outLink));
3637 
3638  roXact = possibleUnsafeConflict->sxactIn;
3639  Assert(MySerializableXact == possibleUnsafeConflict->sxactOut);
3640  Assert(SxactIsReadOnly(roXact));
3641 
3642  /* Mark conflicted if necessary. */
3643  if (isCommit
3644  && MyXactDidWrite
3647  <= roXact->SeqNo.lastCommitBeforeSnapshot))
3648  {
3649  /*
3650  * This releases possibleUnsafeConflict (as well as all other
3651  * possible conflicts for roXact)
3652  */
3653  FlagSxactUnsafe(roXact);
3654  }
3655  else
3656  {
3657  ReleaseRWConflict(possibleUnsafeConflict);
3658 
3659  /*
3660  * If we were the last possible conflict, flag it safe. The
3661  * transaction can now safely release its predicate locks (but
3662  * that transaction's backend has to do that itself).
3663  */
3664  if (SHMQueueEmpty(&roXact->possibleUnsafeConflicts))
3665  roXact->flags |= SXACT_FLAG_RO_SAFE;
3666  }
3667 
3668  /*
3669  * Wake up the process for a waiting DEFERRABLE transaction if we
3670  * now know it's either safe or conflicted.
3671  */
3672  if (SxactIsDeferrableWaiting(roXact) &&
3673  (SxactIsROUnsafe(roXact) || SxactIsROSafe(roXact)))
3674  ProcSendSignal(roXact->pgprocno);
3675 
3676  possibleUnsafeConflict = nextConflict;
3677  }
3678  }
3679 
3680  /*
3681  * Check whether it's time to clean up old transactions. This can only be
3682  * done when the last serializable transaction with the oldest xmin among
3683  * serializable transactions completes. We then find the "new oldest"
3684  * xmin and purge any transactions which finished before this transaction
3685  * was launched.
3686  */
3687  needToClear = false;
3689  {
3691  if (--(PredXact->SxactGlobalXminCount) == 0)
3692  {
3694  needToClear = true;
3695  }
3696  }
3697 
3698  LWLockRelease(SerializableXactHashLock);
3699 
3700  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3701 
3702  /* Add this to the list of transactions to check for later cleanup. */
3703  if (isCommit)
3706 
3707  /*
3708  * If we're releasing a RO_SAFE transaction in parallel mode, we'll only
3709  * partially release it. That's necessary because other backends may have
3710  * a reference to it. The leader will release the SERIALIZABLEXACT itself
3711  * at the end of the transaction after workers have stopped running.
3712  */
3713  if (!isCommit)
3715  isReadOnlySafe && IsInParallelMode(),
3716  false);
3717 
3718  LWLockRelease(SerializableFinishedListLock);
3719 
3720  if (needToClear)
3722 
3724 }
static void SetNewSxactGlobalXmin(void)
Definition: predicate.c:3276
#define SxactIsROUnsafe(sxact)
Definition: predicate.c:287
#define SxactIsDeferrableWaiting(sxact)
Definition: predicate.c:285
static void ReleasePredicateLocksLocal(void)
Definition: predicate.c:3727
static void ClearOldPredicateLocks(void)
Definition: predicate.c:3745
static void FlagSxactUnsafe(SERIALIZABLEXACT *sxact)
Definition: predicate.c:750
#define SxactIsOnFinishedList(sxact)
Definition: predicate.c:262
#define SxactIsROSafe(sxact)
Definition: predicate.c:286
static void ReleaseRWConflict(RWConflict conflict)
Definition: predicate.c:742
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize)
Definition: predicate.c:3902
#define SxactIsRolledBack(sxact)
Definition: predicate.c:274
static SERIALIZABLEXACT * SavedSerializableXact
Definition: predicate.c:426
#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(int pgprocno)
Definition: proc.c:1885
SERIALIZABLEXACT * sxactIn
FullTransactionId nextXid
Definition: transam.h:220
#define XidFromFullTransactionId(x)
Definition: transam.h:48
VariableCache ShmemVariableCache
Definition: varsup.c:34
bool IsInParallelMode(void)
Definition: xact.c:1065

References Assert(), PredXactListData::CanPartialClearThrough, ClearOldPredicateLocks(), SERIALIZABLEXACT::commitSeqNo, SERIALIZABLEXACT::earliestOutConflictCommit, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, FirstNormalSerCommitSeqNo, SERIALIZABLEXACT::flags, FlagSxactUnsafe(), SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, InvalidSerializableXact, IsInParallelMode(), IsolationIsSerializable, IsParallelWorker, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, LocalPredicateLockHash, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, MyXactDidWrite, VariableCacheData::nextXid, offsetof, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, ParallelContextActive(), SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, PredXact, SERIALIZABLEXACT::prepareSeqNo, ProcSendSignal(), ReleaseOneSerializableXact(), ReleasePredicateLocksLocal(), ReleaseRWConflict(), SavedSerializableXact, SERIALIZABLEXACT::SeqNo, SetNewSxactGlobalXmin(), ShmemVariableCache, SHMQueueEmpty(), SHMQueueInsertBefore(), SHMQueueNext(), SXACT_FLAG_COMMITTED, SXACT_FLAG_CONFLICT_OUT, SXACT_FLAG_DOOMED, SXACT_FLAG_PARTIALLY_RELEASED, SXACT_FLAG_PREPARED, SXACT_FLAG_READ_ONLY, SXACT_FLAG_RO_SAFE, SXACT_FLAG_ROLLED_BACK, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactHasConflictOut, SxactHasSummaryConflictOut, RWConflictData::sxactIn, SxactIsCommitted, SxactIsDeferrableWaiting, SxactIsDoomed, SxactIsOnFinishedList, SxactIsPartiallyReleased, SxactIsPrepared, SxactIsReadOnly, SxactIsRolledBack, SxactIsROSafe, SxactIsROUnsafe, RWConflictData::sxactOut, TransactionIdEquals, PredXactListData::WritableSxactCount, XidFromFullTransactionId, and SERIALIZABLEXACT::xmin.

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

◆ SetSerializableTransactionSnapshot()

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

Definition at line 1721 of file predicate.c.

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

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

Referenced by SetTransactionSnapshot().

◆ ShareSerializableXact()

SerializableXactHandle ShareSerializableXact ( void  )

Definition at line 5190 of file predicate.c.

5191 {
5192  return MySerializableXact;
5193 }

References MySerializableXact.

Referenced by InitializeParallelDSM().

◆ TransferPredicateLocksToHeapRelation()

void TransferPredicateLocksToHeapRelation ( Relation  relation)

Definition at line 3148 of file predicate.c.

3149 {
3150  DropAllPredicateLocksFromTable(relation, true);
3151 }
static void DropAllPredicateLocksFromTable(Relation relation, bool transfer)
Definition: predicate.c:2952

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

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_relation

PGDLLIMPORT int max_predicate_locks_per_relation
extern

Definition at line 367 of file predicate.c.

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_xact

PGDLLIMPORT int max_predicate_locks_per_xact
extern

Definition at line 366 of file predicate.c.

Referenced by CreateLocalPredicateLockHash(), and MaxPredicateChildLocks().