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

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

4725 {
4726  SERIALIZABLEXACT *sxact;
4727  TwoPhasePredicateRecord record;
4728  TwoPhasePredicateXactRecord *xactRecord;
4729  TwoPhasePredicateLockRecord *lockRecord;
4730  dlist_iter iter;
4731 
4732  sxact = MySerializableXact;
4733  xactRecord = &(record.data.xactRecord);
4734  lockRecord = &(record.data.lockRecord);
4735 
4737  return;
4738 
4739  /* Generate an xact record for our SERIALIZABLEXACT */
4741  xactRecord->xmin = MySerializableXact->xmin;
4742  xactRecord->flags = MySerializableXact->flags;
4743 
4744  /*
4745  * Note that we don't include the list of conflicts in our out in the
4746  * statefile, because new conflicts can be added even after the
4747  * transaction prepares. We'll just make a conservative assumption during
4748  * recovery instead.
4749  */
4750 
4752  &record, sizeof(record));
4753 
4754  /*
4755  * Generate a lock record for each lock.
4756  *
4757  * To do this, we need to walk the predicate lock list in our sxact rather
4758  * than using the local predicate lock table because the latter is not
4759  * guaranteed to be accurate.
4760  */
4761  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4762 
4763  /*
4764  * No need to take sxact->perXactPredicateListLock in parallel mode
4765  * because there cannot be any parallel workers running while we are
4766  * preparing a transaction.
4767  */
4769 
4770  dlist_foreach(iter, &sxact->predicateLocks)
4771  {
4772  PREDICATELOCK *predlock =
4773  dlist_container(PREDICATELOCK, xactLink, iter.cur);
4774 
4776  lockRecord->target = predlock->tag.myTarget->tag;
4777 
4779  &record, sizeof(record));
4780  }
4781 
4782  LWLockRelease(SerializablePredicateListLock);
4783 }
bool ParallelContextActive(void)
Definition: parallel.c:1001
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
#define IsParallelWorker()
Definition: parallel.h:61
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1195
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
@ LW_SHARED
Definition: lwlock.h:117
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:417
@ TWOPHASEPREDICATERECORD_XACT
@ TWOPHASEPREDICATERECORD_LOCK
#define InvalidSerializableXact
PREDICATELOCKTARGET * myTarget
PREDICATELOCKTARGETTAG tag
PREDICATELOCKTAG tag
PREDICATELOCKTARGETTAG target
TwoPhasePredicateRecordType type
union TwoPhasePredicateRecord::@110 data
TwoPhasePredicateLockRecord lockRecord
TwoPhasePredicateXactRecord xactRecord
dlist_node * cur
Definition: ilist.h:179
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1257
#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 4989 of file predicate.c.

4990 {
4991 
4993 
4994  MySerializableXact = (SERIALIZABLEXACT *) handle;
4997 }
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1874

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

Referenced by ParallelWorkerMain().

◆ CheckForSerializableConflictIn()

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

Definition at line 4270 of file predicate.c.

4271 {
4272  PREDICATELOCKTARGETTAG targettag;
4273 
4274  if (!SerializationNeededForWrite(relation))
4275  return;
4276 
4277  /* Check if someone else has already decided that we need to die */
4279  ereport(ERROR,
4281  errmsg("could not serialize access due to read/write dependencies among transactions"),
4282  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4283  errhint("The transaction might succeed if retried.")));
4284 
4285  /*
4286  * We're doing a write which might cause rw-conflicts now or later.
4287  * Memorize that fact.
4288  */
4289  MyXactDidWrite = true;
4290 
4291  /*
4292  * It is important that we check for locks from the finest granularity to
4293  * the coarsest granularity, so that granularity promotion doesn't cause
4294  * us to miss a lock. The new (coarser) lock will be acquired before the
4295  * old (finer) locks are released.
4296  *
4297  * It is not possible to take and hold a lock across the checks for all
4298  * granularities because each target could be in a separate partition.
4299  */
4300  if (tid != NULL)
4301  {
4303  relation->rd_locator.dbOid,
4304  relation->rd_id,
4307  CheckTargetForConflictsIn(&targettag);
4308  }
4309 
4310  if (blkno != InvalidBlockNumber)
4311  {
4313  relation->rd_locator.dbOid,
4314  relation->rd_id,
4315  blkno);
4316  CheckTargetForConflictsIn(&targettag);
4317  }
4318 
4320  relation->rd_locator.dbOid,
4321  relation->rd_id);
4322  CheckTargetForConflictsIn(&targettag);
4323 }
#define InvalidBlockNumber
Definition: block.h:33
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1229
int errhint(const char *fmt,...)
Definition: elog.c:1316
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#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:418
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:556
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4100
#define SxactIsDoomed(sxact)
Definition: predicate.c:276
#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 3957 of file predicate.c.

3958 {
3959  SERIALIZABLEXIDTAG sxidtag;
3960  SERIALIZABLEXID *sxid;
3961  SERIALIZABLEXACT *sxact;
3962 
3963  if (!SerializationNeededForRead(relation, snapshot))
3964  return;
3965 
3966  /* Check if someone else has already decided that we need to die */
3968  {
3969  ereport(ERROR,
3971  errmsg("could not serialize access due to read/write dependencies among transactions"),
3972  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
3973  errhint("The transaction might succeed if retried.")));
3974  }
3976 
3978  return;
3979 
3980  /*
3981  * Find sxact or summarized info for the top level xid.
3982  */
3983  sxidtag.xid = xid;
3984  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3985  sxid = (SERIALIZABLEXID *)
3986  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
3987  if (!sxid)
3988  {
3989  /*
3990  * Transaction not found in "normal" SSI structures. Check whether it
3991  * got pushed out to SLRU storage for "old committed" transactions.
3992  */
3993  SerCommitSeqNo conflictCommitSeqNo;
3994 
3995  conflictCommitSeqNo = SerialGetMinConflictCommitSeqNo(xid);
3996  if (conflictCommitSeqNo != 0)
3997  {
3998  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4000  || conflictCommitSeqNo
4002  ereport(ERROR,
4004  errmsg("could not serialize access due to read/write dependencies among transactions"),
4005  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4006  errhint("The transaction might succeed if retried.")));
4007 
4010  ereport(ERROR,
4012  errmsg("could not serialize access due to read/write dependencies among transactions"),
4013  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4014  errhint("The transaction might succeed if retried.")));
4015 
4017  }
4018 
4019  /* It's not serializable or otherwise not important. */
4020  LWLockRelease(SerializableXactHashLock);
4021  return;
4022  }
4023  sxact = sxid->myXact;
4024  Assert(TransactionIdEquals(sxact->topXid, xid));
4025  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4026  {
4027  /* Can't conflict with ourself or a transaction that will roll back. */
4028  LWLockRelease(SerializableXactHashLock);
4029  return;
4030  }
4031 
4032  /*
4033  * We have a conflict out to a transaction which has a conflict out to a
4034  * summarized transaction. That summarized transaction must have
4035  * committed first, and we can't tell when it committed in relation to our
4036  * snapshot acquisition, so something needs to be canceled.
4037  */
4038  if (SxactHasSummaryConflictOut(sxact))
4039  {
4040  if (!SxactIsPrepared(sxact))
4041  {
4042  sxact->flags |= SXACT_FLAG_DOOMED;
4043  LWLockRelease(SerializableXactHashLock);
4044  return;
4045  }
4046  else
4047  {
4048  LWLockRelease(SerializableXactHashLock);
4049  ereport(ERROR,
4051  errmsg("could not serialize access due to read/write dependencies among transactions"),
4052  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4053  errhint("The transaction might succeed if retried.")));
4054  }
4055  }
4056 
4057  /*
4058  * If this is a read-only transaction and the writing transaction has
4059  * committed, and it doesn't have a rw-conflict to a transaction which
4060  * committed before it, no conflict.
4061  */
4063  && SxactIsCommitted(sxact)
4064  && !SxactHasSummaryConflictOut(sxact)
4065  && (!SxactHasConflictOut(sxact)
4067  {
4068  /* Read-only transaction will appear to run first. No conflict. */
4069  LWLockRelease(SerializableXactHashLock);
4070  return;
4071  }
4072 
4073  if (!XidIsConcurrent(xid))
4074  {
4075  /* This write was already in our snapshot; no conflict. */
4076  LWLockRelease(SerializableXactHashLock);
4077  return;
4078  }
4079 
4081  {
4082  /* We don't want duplicate conflict records in the list. */
4083  LWLockRelease(SerializableXactHashLock);
4084  return;
4085  }
4086 
4087  /*
4088  * Flag the conflict. But first, if this conflict creates a dangerous
4089  * structure, ereport an error.
4090  */
4092  LWLockRelease(SerializableXactHashLock);
4093 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
@ HASH_FIND
Definition: hsearch.h:113
static bool dlist_is_empty(const dlist_head *head)
Definition: ilist.h:336
@ LW_EXCLUSIVE
Definition: lwlock.h:116
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:606
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:512
#define SxactIsCommitted(sxact)
Definition: predicate.c:273
#define SxactIsReadOnly(sxact)
Definition: predicate.c:277
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:278
#define SxactHasConflictOut(sxact)
Definition: predicate.c:285
#define SxactIsPrepared(sxact)
Definition: predicate.c:274
static HTAB * SerializableXidHash
Definition: predicate.c:392
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4435
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:913
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:3906
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:279
#define InvalidSerCommitSeqNo
#define SXACT_FLAG_DOOMED
uint64 SerCommitSeqNo
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
union SERIALIZABLEXACT::@109 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:432

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

3926 {
3927  if (!SerializationNeededForRead(relation, snapshot))
3928  return false;
3929 
3930  /* Check if someone else has already decided that we need to die */
3932  {
3933  ereport(ERROR,
3935  errmsg("could not serialize access due to read/write dependencies among transactions"),
3936  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
3937  errhint("The transaction might succeed if retried.")));
3938  }
3939 
3940  return true;
3941 }

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

1006 {
1007  int tailPage;
1008 
1009  LWLockAcquire(SerialSLRULock, LW_EXCLUSIVE);
1010 
1011  /* Exit quickly if the SLRU is currently not in use. */
1012  if (serialControl->headPage < 0)
1013  {
1014  LWLockRelease(SerialSLRULock);
1015  return;
1016  }
1017 
1019  {
1020  /* We can truncate the SLRU up to the page containing tailXid */
1021  tailPage = SerialPage(serialControl->tailXid);
1022  }
1023  else
1024  {
1025  /*----------
1026  * The SLRU is no longer needed. Truncate to head before we set head
1027  * invalid.
1028  *
1029  * XXX: It's possible that the SLRU is not needed again until XID
1030  * wrap-around has happened, so that the segment containing headPage
1031  * that we leave behind will appear to be new again. In that case it
1032  * won't be removed until XID horizon advances enough to make it
1033  * current again.
1034  *
1035  * XXX: This should happen in vac_truncate_clog(), not in checkpoints.
1036  * Consider this scenario, starting from a system with no in-progress
1037  * transactions and VACUUM FREEZE having maximized oldestXact:
1038  * - Start a SERIALIZABLE transaction.
1039  * - Start, finish, and summarize a SERIALIZABLE transaction, creating
1040  * one SLRU page.
1041  * - Consume XIDs to reach xidStopLimit.
1042  * - Finish all transactions. Due to the long-running SERIALIZABLE
1043  * transaction, earlier checkpoints did not touch headPage. The
1044  * next checkpoint will change it, but that checkpoint happens after
1045  * the end of the scenario.
1046  * - VACUUM to advance XID limits.
1047  * - Consume ~2M XIDs, crossing the former xidWrapLimit.
1048  * - Start, finish, and summarize a SERIALIZABLE transaction.
1049  * SerialAdd() declines to create the targetPage, because headPage
1050  * is not regarded as in the past relative to that targetPage. The
1051  * transaction instigating the summarize fails in
1052  * SimpleLruReadPage().
1053  */
1054  tailPage = serialControl->headPage;
1055  serialControl->headPage = -1;
1056  }
1057 
1058  LWLockRelease(SerialSLRULock);
1059 
1060  /* Truncate away pages that are no longer required */
1061  SimpleLruTruncate(SerialSlruCtl, tailPage);
1062 
1063  /*
1064  * Write dirty SLRU pages to disk
1065  *
1066  * This is not actually necessary from a correctness point of view. We do
1067  * it merely as a debugging aid.
1068  *
1069  * We're doing this after the truncation to avoid writing pages right
1070  * before deleting the file in which they sit, which would be completely
1071  * pointless.
1072  */
1074 }
#define SerialPage(xid)
Definition: predicate.c:339
static SerialControl serialControl
Definition: predicate.c:350
#define SerialSlruCtl
Definition: predicate.c:322
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1157
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1227
TransactionId tailXid
Definition: predicate.c:345

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

4354 {
4355  HASH_SEQ_STATUS seqstat;
4356  PREDICATELOCKTARGET *target;
4357  Oid dbId;
4358  Oid heapId;
4359  int i;
4360 
4361  /*
4362  * Bail out quickly if there are no serializable transactions running.
4363  * It's safe to check this without taking locks because the caller is
4364  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4365  * would matter here can be acquired while that is held.
4366  */
4368  return;
4369 
4370  if (!SerializationNeededForWrite(relation))
4371  return;
4372 
4373  /*
4374  * We're doing a write which might cause rw-conflicts now or later.
4375  * Memorize that fact.
4376  */
4377  MyXactDidWrite = true;
4378 
4379  Assert(relation->rd_index == NULL); /* not an index relation */
4380 
4381  dbId = relation->rd_locator.dbOid;
4382  heapId = relation->rd_id;
4383 
4384  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
4385  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4387  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4388 
4389  /* Scan through target list */
4391 
4392  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4393  {
4394  dlist_mutable_iter iter;
4395 
4396  /*
4397  * Check whether this is a target which needs attention.
4398  */
4399  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4400  continue; /* wrong relation id */
4401  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4402  continue; /* wrong database id */
4403 
4404  /*
4405  * Loop through locks for this target and flag conflicts.
4406  */
4407  dlist_foreach_modify(iter, &target->predicateLocks)
4408  {
4409  PREDICATELOCK *predlock =
4410  dlist_container(PREDICATELOCK, targetLink, iter.cur);
4411 
4412  if (predlock->tag.myXact != MySerializableXact
4414  {
4416  }
4417  }
4418  }
4419 
4420  /* Release locks in reverse order */
4421  LWLockRelease(SerializableXactHashLock);
4422  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4424  LWLockRelease(SerializablePredicateListLock);
4425 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1431
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1421
#define dlist_foreach_modify(iter, lhead)
Definition: ilist.h:640
int i
Definition: isn.c:73
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:103
unsigned int Oid
Definition: postgres_ext.h:31
static PredXactList PredXact
Definition: predicate.c:380
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:257
static HTAB * PredicateLockTargetHash
Definition: predicate.c:393
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
SERIALIZABLEXACT * myXact
TransactionId SxactGlobalXmin
Form_pg_index rd_index
Definition: rel.h:191
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 1616 of file predicate.c.

1617 {
1619 
1620  /*
1621  * Can't use serializable mode while recovery is still active, as it is,
1622  * for example, on a hot standby. We could get here despite the check in
1623  * check_transaction_isolation() if default_transaction_isolation is set
1624  * to serializable, so phrase the hint accordingly.
1625  */
1626  if (RecoveryInProgress())
1627  ereport(ERROR,
1628  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1629  errmsg("cannot use serializable mode in a hot standby"),
1630  errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1631  errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1632 
1633  /*
1634  * A special optimization is available for SERIALIZABLE READ ONLY
1635  * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1636  * thereby avoid all SSI overhead once it's running.
1637  */
1639  return GetSafeSnapshot(snapshot);
1640 
1641  return GetSerializableTransactionSnapshotInt(snapshot,
1642  NULL, InvalidPid);
1643 }
int errdetail(const char *fmt,...)
Definition: elog.c:1202
#define InvalidPid
Definition: miscadmin.h:32
static Snapshot GetSafeSnapshot(Snapshot origSnapshot)
Definition: predicate.c:1492
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1698
bool XactDeferrable
Definition: xact.c:85
bool XactReadOnly
Definition: xact.c:82
#define IsolationIsSerializable()
Definition: xact.h:52
bool RecoveryInProgress(void)
Definition: xlog.c:5921

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

1090 {
1091  HASHCTL info;
1092  long max_table_size;
1093  Size requestSize;
1094  bool found;
1095 
1096 #ifndef EXEC_BACKEND
1098 #endif
1099 
1100  /*
1101  * Compute size of predicate lock target hashtable. Note these
1102  * calculations must agree with PredicateLockShmemSize!
1103  */
1104  max_table_size = NPREDICATELOCKTARGETENTS();
1105 
1106  /*
1107  * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1108  * per-predicate-lock-target information.
1109  */
1110  info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1111  info.entrysize = sizeof(PREDICATELOCKTARGET);
1113 
1114  PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1115  max_table_size,
1116  max_table_size,
1117  &info,
1118  HASH_ELEM | HASH_BLOBS |
1120 
1121  /*
1122  * Reserve a dummy entry in the hash table; we use it to make sure there's
1123  * always one entry available when we need to split or combine a page,
1124  * because running out of space there could mean aborting a
1125  * non-serializable transaction.
1126  */
1127  if (!IsUnderPostmaster)
1128  {
1130  HASH_ENTER, &found);
1131  Assert(!found);
1132  }
1133 
1134  /* Pre-calculate the hash and partition lock of the scratch entry */
1137 
1138  /*
1139  * Allocate hash table for PREDICATELOCK structs. This stores per
1140  * xact-lock-of-a-target information.
1141  */
1142  info.keysize = sizeof(PREDICATELOCKTAG);
1143  info.entrysize = sizeof(PREDICATELOCK);
1144  info.hash = predicatelock_hash;
1146 
1147  /* Assume an average of 2 xacts per target */
1148  max_table_size *= 2;
1149 
1150  PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1151  max_table_size,
1152  max_table_size,
1153  &info,
1156 
1157  /*
1158  * Compute size for serializable transaction hashtable. Note these
1159  * calculations must agree with PredicateLockShmemSize!
1160  */
1161  max_table_size = (MaxBackends + max_prepared_xacts);
1162 
1163  /*
1164  * Allocate a list to hold information on transactions participating in
1165  * predicate locking.
1166  *
1167  * Assume an average of 10 predicate locking transactions per backend.
1168  * This allows aggressive cleanup while detail is present before data must
1169  * be summarized for storage in SLRU and the "dummy" transaction.
1170  */
1171  max_table_size *= 10;
1172 
1173  PredXact = ShmemInitStruct("PredXactList",
1175  &found);
1176  Assert(found == IsUnderPostmaster);
1177  if (!found)
1178  {
1179  int i;
1180 
1189  requestSize = mul_size((Size) max_table_size,
1190  sizeof(SERIALIZABLEXACT));
1191  PredXact->element = ShmemAlloc(requestSize);
1192  /* Add all elements to available list, clean. */
1193  memset(PredXact->element, 0, requestSize);
1194  for (i = 0; i < max_table_size; i++)
1195  {
1199  }
1216  }
1217  /* This never changes, so let's keep a local copy. */
1219 
1220  /*
1221  * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1222  * information for serializable transactions which have accessed data.
1223  */
1224  info.keysize = sizeof(SERIALIZABLEXIDTAG);
1225  info.entrysize = sizeof(SERIALIZABLEXID);
1226 
1227  SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1228  max_table_size,
1229  max_table_size,
1230  &info,
1231  HASH_ELEM | HASH_BLOBS |
1232  HASH_FIXED_SIZE);
1233 
1234  /*
1235  * Allocate space for tracking rw-conflicts in lists attached to the
1236  * transactions.
1237  *
1238  * Assume an average of 5 conflicts per transaction. Calculations suggest
1239  * that this will prevent resource exhaustion in even the most pessimal
1240  * loads up to max_connections = 200 with all 200 connections pounding the
1241  * database with serializable transactions. Beyond that, there may be
1242  * occasional transactions canceled when trying to flag conflicts. That's
1243  * probably OK.
1244  */
1245  max_table_size *= 5;
1246 
1247  RWConflictPool = ShmemInitStruct("RWConflictPool",
1249  &found);
1250  Assert(found == IsUnderPostmaster);
1251  if (!found)
1252  {
1253  int i;
1254 
1256  requestSize = mul_size((Size) max_table_size,
1258  RWConflictPool->element = ShmemAlloc(requestSize);
1259  /* Add all elements to available list, clean. */
1260  memset(RWConflictPool->element, 0, requestSize);
1261  for (i = 0; i < max_table_size; i++)
1262  {
1265  }
1266  }
1267 
1268  /*
1269  * Create or attach to the header for the list of finished serializable
1270  * transactions.
1271  */
1273  ShmemInitStruct("FinishedSerializableTransactions",
1274  sizeof(dlist_head),
1275  &found);
1276  Assert(found == IsUnderPostmaster);
1277  if (!found)
1279 
1280  /*
1281  * Initialize the SLRU storage for old committed serializable
1282  * transactions.
1283  */
1284  SerialInit();
1285 }
size_t Size
Definition: c.h:589
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
static void dlist_init(dlist_head *head)
Definition: ilist.h:314
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
static void dlist_node_init(dlist_node *node)
Definition: ilist.h:325
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:74
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:730
@ LWTRANCHE_PER_XACT_PREDICATE_LIST
Definition: lwlock.h:204
static HTAB * PredicateLockHash
Definition: predicate.c:394
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:299
static LWLock * ScratchPartitionLock
Definition: predicate.c:404
static uint32 ScratchTargetTagHash
Definition: predicate.c:403
static uint32 predicatelock_hash(const void *key, Size keysize)
Definition: predicate.c:1353
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:578
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:358
static void SerialInit(void)
Definition: predicate.c:802
static dlist_head * FinishedSerializableTransactions
Definition: predicate.c:395
static const PREDICATELOCKTARGETTAG ScratchTargetTag
Definition: predicate.c:402
#define NPREDICATELOCKTARGETENTS()
Definition: predicate.c:260
static RWConflictPoolHeader RWConflictPool
Definition: predicate.c:386
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:254
#define RWConflictDataSize
#define FirstNormalSerCommitSeqNo
struct PREDICATELOCKTAG PREDICATELOCKTAG
#define PredXactListDataSize
#define RWConflictPoolHeaderDataSize
struct SERIALIZABLEXIDTAG SERIALIZABLEXIDTAG
struct PREDICATELOCKTARGET PREDICATELOCKTARGET
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
struct SERIALIZABLEXID SERIALIZABLEXID
#define SXACT_FLAG_COMMITTED
struct PREDICATELOCK PREDICATELOCK
#define INVALID_PGPROCNO
Definition: proc.h:85
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
Size keysize
Definition: hsearch.h:75
HashValueFunc hash
Definition: hsearch.h:78
Size entrysize
Definition: hsearch.h:76
long num_partitions
Definition: hsearch.h:68
SERIALIZABLEXACT * element
SerCommitSeqNo LastSxactCommitSeqNo
SerCommitSeqNo CanPartialClearThrough
SERIALIZABLEXACT * OldCommittedSxact
SerCommitSeqNo HavePartialClearedThrough
VirtualTransactionId vxid
dlist_head possibleUnsafeConflicts
SerCommitSeqNo prepareSeqNo
SerCommitSeqNo commitSeqNo
TransactionId finishedBefore
#define InvalidTransactionId
Definition: transam.h:31
int max_prepared_xacts
Definition: twophase.c:117

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_PGPROCNO, 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 CreateSharedMemoryAndSemaphores().

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

Definition at line 1942 of file predicate.c.

1943 {
1944  PREDICATELOCKTARGETTAG targettag;
1945  uint32 targettaghash;
1946  LWLock *partitionLock;
1947  PREDICATELOCKTARGET *target;
1948 
1950  relation->rd_locator.dbOid,
1951  relation->rd_id,
1952  blkno);
1953 
1954  targettaghash = PredicateLockTargetTagHashCode(&targettag);
1955  partitionLock = PredicateLockHashPartitionLock(targettaghash);
1956  LWLockAcquire(partitionLock, LW_SHARED);
1957  target = (PREDICATELOCKTARGET *)
1959  &targettag, targettaghash,
1960  HASH_FIND, NULL);
1961  LWLockRelease(partitionLock);
1962 
1963  return (target != NULL);
1964 }
unsigned int uint32
Definition: c.h:490
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:966
Definition: lwlock.h:41

References RelFileLocator::dbOid, HASH_FIND, hash_search_with_hash_value(), LW_SHARED, LWLockAcquire(), LWLockRelease(), PredicateLockHashPartitionLock, PredicateLockTargetHash, PredicateLockTargetTagHashCode, RelationData::rd_id, RelationData::rd_locator, and SET_PREDICATELOCKTARGETTAG_PAGE.

◆ PostPrepare_PredicateLocks()

void PostPrepare_PredicateLocks ( TransactionId  xid)

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4637 of file predicate.c.

4638 {
4639  dlist_iter near_iter;
4640 
4642  return;
4643 
4645 
4646  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4647 
4648  /*
4649  * Check if someone else has already decided that we need to die. Since
4650  * we set our own DOOMED flag when partially releasing, ignore in that
4651  * case.
4652  */
4655  {
4656  LWLockRelease(SerializableXactHashLock);
4657  ereport(ERROR,
4659  errmsg("could not serialize access due to read/write dependencies among transactions"),
4660  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4661  errhint("The transaction might succeed if retried.")));
4662  }
4663 
4665  {
4666  RWConflict nearConflict =
4667  dlist_container(RWConflictData, inLink, near_iter.cur);
4668 
4669  if (!SxactIsCommitted(nearConflict->sxactOut)
4670  && !SxactIsDoomed(nearConflict->sxactOut))
4671  {
4672  dlist_iter far_iter;
4673 
4674  dlist_foreach(far_iter, &nearConflict->sxactOut->inConflicts)
4675  {
4676  RWConflict farConflict =
4677  dlist_container(RWConflictData, inLink, far_iter.cur);
4678 
4679  if (farConflict->sxactOut == MySerializableXact
4680  || (!SxactIsCommitted(farConflict->sxactOut)
4681  && !SxactIsReadOnly(farConflict->sxactOut)
4682  && !SxactIsDoomed(farConflict->sxactOut)))
4683  {
4684  /*
4685  * Normally, we kill the pivot transaction to make sure we
4686  * make progress if the failing transaction is retried.
4687  * However, we can't kill it if it's already prepared, so
4688  * in that case we commit suicide instead.
4689  */
4690  if (SxactIsPrepared(nearConflict->sxactOut))
4691  {
4692  LWLockRelease(SerializableXactHashLock);
4693  ereport(ERROR,
4695  errmsg("could not serialize access due to read/write dependencies among transactions"),
4696  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4697  errhint("The transaction might succeed if retried.")));
4698  }
4699  nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4700  break;
4701  }
4702  }
4703  }
4704  }
4705 
4708 
4709  LWLockRelease(SerializableXactHashLock);
4710 }
#define SxactIsPartiallyReleased(sxact)
Definition: predicate.c:289
#define SXACT_FLAG_PREPARED
SERIALIZABLEXACT * sxactOut

References Assert(), dlist_iter::cur, dlist_container, dlist_foreach, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::inConflicts, InvalidSerializableXact, IsolationIsSerializable, PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, PredXact, SERIALIZABLEXACT::prepareSeqNo, SXACT_FLAG_DOOMED, SXACT_FLAG_PREPARED, SxactIsCommitted, SxactIsDoomed, SxactIsPartiallyReleased, SxactIsPrepared, SxactIsReadOnly, and RWConflictData::sxactOut.

Referenced by CommitTransaction(), and PrepareTransaction().

◆ predicatelock_twophase_recover()

void predicatelock_twophase_recover ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 4843 of file predicate.c.

4845 {
4846  TwoPhasePredicateRecord *record;
4847 
4848  Assert(len == sizeof(TwoPhasePredicateRecord));
4849 
4850  record = (TwoPhasePredicateRecord *) recdata;
4851 
4852  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
4853  (record->type == TWOPHASEPREDICATERECORD_LOCK));
4854 
4855  if (record->type == TWOPHASEPREDICATERECORD_XACT)
4856  {
4857  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4858  TwoPhasePredicateXactRecord *xactRecord;
4859  SERIALIZABLEXACT *sxact;
4860  SERIALIZABLEXID *sxid;
4861  SERIALIZABLEXIDTAG sxidtag;
4862  bool found;
4863 
4864  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4865 
4866  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4867  sxact = CreatePredXact();
4868  if (!sxact)
4869  ereport(ERROR,
4870  (errcode(ERRCODE_OUT_OF_MEMORY),
4871  errmsg("out of shared memory")));
4872 
4873  /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
4874  sxact->vxid.backendId = InvalidBackendId;
4876  sxact->pid = 0;
4877  sxact->pgprocno = INVALID_PGPROCNO;
4878 
4879  /* a prepared xact hasn't committed yet */
4883 
4885 
4886  /*
4887  * Don't need to track this; no transactions running at the time the
4888  * recovered xact started are still active, except possibly other
4889  * prepared xacts and we don't care whether those are RO_SAFE or not.
4890  */
4892 
4893  dlist_init(&(sxact->predicateLocks));
4894  dlist_node_init(&sxact->finishedLink);
4895 
4896  sxact->topXid = xid;
4897  sxact->xmin = xactRecord->xmin;
4898  sxact->flags = xactRecord->flags;
4899  Assert(SxactIsPrepared(sxact));
4900  if (!SxactIsReadOnly(sxact))
4901  {
4905  }
4906 
4907  /*
4908  * We don't know whether the transaction had any conflicts or not, so
4909  * we'll conservatively assume that it had both a conflict in and a
4910  * conflict out, and represent that with the summary conflict flags.
4911  */
4912  dlist_init(&(sxact->outConflicts));
4913  dlist_init(&(sxact->inConflicts));
4916 
4917  /* Register the transaction's xid */
4918  sxidtag.xid = xid;
4920  &sxidtag,
4921  HASH_ENTER, &found);
4922  Assert(sxid != NULL);
4923  Assert(!found);
4924  sxid->myXact = (SERIALIZABLEXACT *) sxact;
4925 
4926  /*
4927  * Update global xmin. Note that this is a special case compared to
4928  * registering a normal transaction, because the global xmin might go
4929  * backwards. That's OK, because until recovery is over we're not
4930  * going to complete any transactions or create any non-prepared
4931  * transactions, so there's no danger of throwing away.
4932  */
4935  {
4936  PredXact->SxactGlobalXmin = sxact->xmin;
4938  SerialSetActiveSerXmin(sxact->xmin);
4939  }
4940  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
4941  {
4944  }
4945 
4946  LWLockRelease(SerializableXactHashLock);
4947  }
4948  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
4949  {
4950  /* Lock record. Recreate the PREDICATELOCK */
4951  TwoPhasePredicateLockRecord *lockRecord;
4952  SERIALIZABLEXID *sxid;
4953  SERIALIZABLEXACT *sxact;
4954  SERIALIZABLEXIDTAG sxidtag;
4955  uint32 targettaghash;
4956 
4957  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
4958  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
4959 
4960  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4961  sxidtag.xid = xid;
4962  sxid = (SERIALIZABLEXID *)
4963  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4964  LWLockRelease(SerializableXactHashLock);
4965 
4966  Assert(sxid != NULL);
4967  sxact = sxid->myXact;
4968  Assert(sxact != InvalidSerializableXact);
4969 
4970  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
4971  }
4972 }
#define InvalidBackendId
Definition: backendid.h:23
uint32 LocalTransactionId
Definition: c.h:638
const void size_t len
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2387
static void SerialSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:954
#define SXACT_FLAG_SUMMARY_CONFLICT_IN
#define RecoverySerCommitSeqNo
LocalTransactionId localTransactionId
Definition: lock.h:62
BackendId backendId
Definition: lock.h:61
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:314

References Assert(), VirtualTransactionId::backendId, 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_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(), 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 2533 of file predicate.c.

2534 {
2536 
2537  if (!SerializationNeededForRead(relation, snapshot))
2538  return;
2539 
2541  relation->rd_locator.dbOid,
2542  relation->rd_id,
2543  blkno);
2544  PredicateLockAcquire(&tag);
2545 }
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2451

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

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

◆ PredicateLockPageCombine()

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

Definition at line 3163 of file predicate.c.

3165 {
3166  /*
3167  * Page combines differ from page splits in that we ought to be able to
3168  * remove the locks on the old page after transferring them to the new
3169  * page, instead of duplicating them. However, because we can't edit other
3170  * backends' local lock tables, removing the old lock would leave them
3171  * with an entry in their LocalPredicateLockHash for a lock they're not
3172  * holding, which isn't acceptable. So we wind up having to do the same
3173  * work as a page split, acquiring a lock on the new page and keeping the
3174  * old page locked too. That can lead to some false positives, but should
3175  * be rare in practice.
3176  */
3177  PredicateLockPageSplit(relation, oldblkno, newblkno);
3178 }
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3078

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

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

Definition at line 3078 of file predicate.c.

3080 {
3081  PREDICATELOCKTARGETTAG oldtargettag;
3082  PREDICATELOCKTARGETTAG newtargettag;
3083  bool success;
3084 
3085  /*
3086  * Bail out quickly if there are no serializable transactions running.
3087  *
3088  * It's safe to do this check without taking any additional locks. Even if
3089  * a serializable transaction starts concurrently, we know it can't take
3090  * any SIREAD locks on the page being split because the caller is holding
3091  * the associated buffer page lock. Memory reordering isn't an issue; the
3092  * memory barrier in the LWLock acquisition guarantees that this read
3093  * occurs while the buffer page lock is held.
3094  */
3096  return;
3097 
3098  if (!PredicateLockingNeededForRelation(relation))
3099  return;
3100 
3101  Assert(oldblkno != newblkno);
3102  Assert(BlockNumberIsValid(oldblkno));
3103  Assert(BlockNumberIsValid(newblkno));
3104 
3105  SET_PREDICATELOCKTARGETTAG_PAGE(oldtargettag,
3106  relation->rd_locator.dbOid,
3107  relation->rd_id,
3108  oldblkno);
3109  SET_PREDICATELOCKTARGETTAG_PAGE(newtargettag,
3110  relation->rd_locator.dbOid,
3111  relation->rd_id,
3112  newblkno);
3113 
3114  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
3115 
3116  /*
3117  * Try copying the locks over to the new page's tag, creating it if
3118  * necessary.
3119  */
3121  newtargettag,
3122  false);
3123 
3124  if (!success)
3125  {
3126  /*
3127  * No more predicate lock entries are available. Failure isn't an
3128  * option here, so promote the page lock to a relation lock.
3129  */
3130 
3131  /* Get the parent relation lock's lock tag */
3132  success = GetParentPredicateLockTag(&oldtargettag,
3133  &newtargettag);
3134  Assert(success);
3135 
3136  /*
3137  * Move the locks to the parent. This shouldn't fail.
3138  *
3139  * Note that here we are removing locks held by other backends,
3140  * leading to a possible inconsistency in their local lock hash table.
3141  * This is OK because we're replacing it with a lock that covers the
3142  * old one.
3143  */
3145  newtargettag,
3146  true);
3147  Assert(success);
3148  }
3149 
3150  LWLockRelease(SerializablePredicateListLock);
3151 }
static bool BlockNumberIsValid(BlockNumber blockNumber)
Definition: block.h:71
static bool success
Definition: initdb.c:187
static bool PredicateLockingNeededForRelation(Relation relation)
Definition: predicate.c:494
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:2006
static bool TransferPredicateLocksToNewTarget(PREDICATELOCKTARGETTAG oldtargettag, PREDICATELOCKTARGETTAG newtargettag, bool removeOld)
Definition: predicate.c:2664

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

2511 {
2513 
2514  if (!SerializationNeededForRead(relation, snapshot))
2515  return;
2516 
2518  relation->rd_locator.dbOid,
2519  relation->rd_id);
2520  PredicateLockAcquire(&tag);
2521 }

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

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

◆ PredicateLockShmemSize()

Size PredicateLockShmemSize ( void  )

Definition at line 1291 of file predicate.c.

1292 {
1293  Size size = 0;
1294  long max_table_size;
1295 
1296  /* predicate lock target hash table */
1297  max_table_size = NPREDICATELOCKTARGETENTS();
1298  size = add_size(size, hash_estimate_size(max_table_size,
1299  sizeof(PREDICATELOCKTARGET)));
1300 
1301  /* predicate lock hash table */
1302  max_table_size *= 2;
1303  size = add_size(size, hash_estimate_size(max_table_size,
1304  sizeof(PREDICATELOCK)));
1305 
1306  /*
1307  * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
1308  * margin.
1309  */
1310  size = add_size(size, size / 10);
1311 
1312  /* transaction list */
1313  max_table_size = MaxBackends + max_prepared_xacts;
1314  max_table_size *= 10;
1315  size = add_size(size, PredXactListDataSize);
1316  size = add_size(size, mul_size((Size) max_table_size,
1317  sizeof(SERIALIZABLEXACT)));
1318 
1319  /* transaction xid table */
1320  size = add_size(size, hash_estimate_size(max_table_size,
1321  sizeof(SERIALIZABLEXID)));
1322 
1323  /* rw-conflict pool */
1324  max_table_size *= 5;
1325  size = add_size(size, RWConflictPoolHeaderDataSize);
1326  size = add_size(size, mul_size((Size) max_table_size,
1328 
1329  /* Head for list of finished serializable transactions. */
1330  size = add_size(size, sizeof(dlist_head));
1331 
1332  /* Shared memory structures for SLRU tracking of old committed xids. */
1333  size = add_size(size, sizeof(SerialControlData));
1335 
1336  return size;
1337 }
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:781
#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, RWConflictDataSize, RWConflictPoolHeaderDataSize, and SimpleLruShmemSize().

Referenced by CalculateShmemSize().

◆ PredicateLockTID()

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

Definition at line 2555 of file predicate.c.

2557 {
2559 
2560  if (!SerializationNeededForRead(relation, snapshot))
2561  return;
2562 
2563  /*
2564  * Return if this xact wrote it.
2565  */
2566  if (relation->rd_index == NULL)
2567  {
2568  /* If we wrote it; we already have a write lock. */
2569  if (TransactionIdIsCurrentTransactionId(tuple_xid))
2570  return;
2571  }
2572 
2573  /*
2574  * Do quick-but-not-definitive test for a relation lock first. This will
2575  * never cause a return when the relation is *not* locked, but will
2576  * occasionally let the check continue when there really *is* a relation
2577  * level lock.
2578  */
2580  relation->rd_locator.dbOid,
2581  relation->rd_id);
2582  if (PredicateLockExists(&tag))
2583  return;
2584 
2586  relation->rd_locator.dbOid,
2587  relation->rd_id,
2590  PredicateLockAcquire(&tag);
2591 }
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:1979
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:926

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

4817 {
4818  SERIALIZABLEXID *sxid;
4819  SERIALIZABLEXIDTAG sxidtag;
4820 
4821  sxidtag.xid = xid;
4822 
4823  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4824  sxid = (SERIALIZABLEXID *)
4825  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4826  LWLockRelease(SerializableXactHashLock);
4827 
4828  /* xid will not be found if it wasn't a serializable transaction */
4829  if (sxid == NULL)
4830  return;
4831 
4832  /* Release its locks */
4833  MySerializableXact = sxid->myXact;
4834  MyXactDidWrite = true; /* conservatively assume that we wrote
4835  * something */
4836  ReleasePredicateLocks(isCommit, false);
4837 }
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3246

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

1894 {
1895  SERIALIZABLEXIDTAG sxidtag;
1896  SERIALIZABLEXID *sxid;
1897  bool found;
1898 
1899  /*
1900  * If we're not tracking predicate lock data for this transaction, we
1901  * should ignore the request and return quickly.
1902  */
1904  return;
1905 
1906  /* We should have a valid XID and be at the top level. */
1908 
1909  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1910 
1911  /* This should only be done once per transaction. */
1913 
1914  MySerializableXact->topXid = xid;
1915 
1916  sxidtag.xid = xid;
1918  &sxidtag,
1919  HASH_ENTER, &found);
1920  Assert(!found);
1921 
1922  /* Initialize the structure. */
1923  sxid->myXact = MySerializableXact;
1924  LWLockRelease(SerializableXactHashLock);
1925 }

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

3247 {
3248  bool partiallyReleasing = false;
3249  bool needToClear;
3250  SERIALIZABLEXACT *roXact;
3251  dlist_mutable_iter iter;
3252 
3253  /*
3254  * We can't trust XactReadOnly here, because a transaction which started
3255  * as READ WRITE can show as READ ONLY later, e.g., within
3256  * subtransactions. We want to flag a transaction as READ ONLY if it
3257  * commits without writing so that de facto READ ONLY transactions get the
3258  * benefit of some RO optimizations, so we will use this local variable to
3259  * get some cleanup logic right which is based on whether the transaction
3260  * was declared READ ONLY at the top level.
3261  */
3262  bool topLevelIsDeclaredReadOnly;
3263 
3264  /* We can't be both committing and releasing early due to RO_SAFE. */
3265  Assert(!(isCommit && isReadOnlySafe));
3266 
3267  /* Are we at the end of a transaction, that is, a commit or abort? */
3268  if (!isReadOnlySafe)
3269  {
3270  /*
3271  * Parallel workers mustn't release predicate locks at the end of
3272  * their transaction. The leader will do that at the end of its
3273  * transaction.
3274  */
3275  if (IsParallelWorker())
3276  {
3278  return;
3279  }
3280 
3281  /*
3282  * By the time the leader in a parallel query reaches end of
3283  * transaction, it has waited for all workers to exit.
3284  */
3286 
3287  /*
3288  * If the leader in a parallel query earlier stashed a partially
3289  * released SERIALIZABLEXACT for final clean-up at end of transaction
3290  * (because workers might still have been accessing it), then it's
3291  * time to restore it.
3292  */
3294  {
3299  }
3300  }
3301 
3303  {
3304  Assert(LocalPredicateLockHash == NULL);
3305  return;
3306  }
3307 
3308  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3309 
3310  /*
3311  * If the transaction is committing, but it has been partially released
3312  * already, then treat this as a roll back. It was marked as rolled back.
3313  */
3315  isCommit = false;
3316 
3317  /*
3318  * If we're called in the middle of a transaction because we discovered
3319  * that the SXACT_FLAG_RO_SAFE flag was set, then we'll partially release
3320  * it (that is, release the predicate locks and conflicts, but not the
3321  * SERIALIZABLEXACT itself) if we're the first backend to have noticed.
3322  */
3323  if (isReadOnlySafe && IsInParallelMode())
3324  {
3325  /*
3326  * The leader needs to stash a pointer to it, so that it can
3327  * completely release it at end-of-transaction.
3328  */
3329  if (!IsParallelWorker())
3331 
3332  /*
3333  * The first backend to reach this condition will partially release
3334  * the SERIALIZABLEXACT. All others will just clear their
3335  * backend-local state so that they stop doing SSI checks for the rest
3336  * of the transaction.
3337  */
3339  {
3340  LWLockRelease(SerializableXactHashLock);
3342  return;
3343  }
3344  else
3345  {
3347  partiallyReleasing = true;
3348  /* ... and proceed to perform the partial release below. */
3349  }
3350  }
3351  Assert(!isCommit || SxactIsPrepared(MySerializableXact));
3352  Assert(!isCommit || !SxactIsDoomed(MySerializableXact));
3356 
3357  /* may not be serializable during COMMIT/ROLLBACK PREPARED */
3359 
3360  /* We'd better not already be on the cleanup list. */
3362 
3363  topLevelIsDeclaredReadOnly = SxactIsReadOnly(MySerializableXact);
3364 
3365  /*
3366  * We don't hold XidGenLock lock here, assuming that TransactionId is
3367  * atomic!
3368  *
3369  * If this value is changing, we don't care that much whether we get the
3370  * old or new value -- it is just used to determine how far
3371  * SxactGlobalXmin must advance before this transaction can be fully
3372  * cleaned up. The worst that could happen is we wait for one more
3373  * transaction to complete before freeing some RAM; correctness of visible
3374  * behavior is not affected.
3375  */
3377 
3378  /*
3379  * If it's not a commit it's either a rollback or a read-only transaction
3380  * flagged SXACT_FLAG_RO_SAFE, and we can clear our locks immediately.
3381  */
3382  if (isCommit)
3383  {
3386  /* Recognize implicit read-only transaction (commit without write). */
3387  if (!MyXactDidWrite)
3389  }
3390  else
3391  {
3392  /*
3393  * The DOOMED flag indicates that we intend to roll back this
3394  * transaction and so it should not cause serialization failures for
3395  * other transactions that conflict with it. Note that this flag might
3396  * already be set, if another backend marked this transaction for
3397  * abort.
3398  *
3399  * The ROLLED_BACK flag further indicates that ReleasePredicateLocks
3400  * has been called, and so the SerializableXact is eligible for
3401  * cleanup. This means it should not be considered when calculating
3402  * SxactGlobalXmin.
3403  */
3406 
3407  /*
3408  * If the transaction was previously prepared, but is now failing due
3409  * to a ROLLBACK PREPARED or (hopefully very rare) error after the
3410  * prepare, clear the prepared flag. This simplifies conflict
3411  * checking.
3412  */
3414  }
3415 
3416  if (!topLevelIsDeclaredReadOnly)
3417  {
3419  if (--(PredXact->WritableSxactCount) == 0)
3420  {
3421  /*
3422  * Release predicate locks and rw-conflicts in for all committed
3423  * transactions. There are no longer any transactions which might
3424  * conflict with the locks and no chance for new transactions to
3425  * overlap. Similarly, existing conflicts in can't cause pivots,
3426  * and any conflicts in which could have completed a dangerous
3427  * structure would already have caused a rollback, so any
3428  * remaining ones must be benign.
3429  */
3431  }
3432  }
3433  else
3434  {
3435  /*
3436  * Read-only transactions: clear the list of transactions that might
3437  * make us unsafe. Note that we use 'inLink' for the iteration as
3438  * opposed to 'outLink' for the r/w xacts.
3439  */
3441  {
3442  RWConflict possibleUnsafeConflict =
3443  dlist_container(RWConflictData, inLink, iter.cur);
3444 
3445  Assert(!SxactIsReadOnly(possibleUnsafeConflict->sxactOut));
3446  Assert(MySerializableXact == possibleUnsafeConflict->sxactIn);
3447 
3448  ReleaseRWConflict(possibleUnsafeConflict);
3449  }
3450  }
3451 
3452  /* Check for conflict out to old committed transactions. */
3453  if (isCommit
3456  {
3457  /*
3458  * we don't know which old committed transaction we conflicted with,
3459  * so be conservative and use FirstNormalSerCommitSeqNo here
3460  */
3464  }
3465 
3466  /*
3467  * Release all outConflicts to committed transactions. If we're rolling
3468  * back clear them all. Set SXACT_FLAG_CONFLICT_OUT if any point to
3469  * previously committed transactions.
3470  */
3472  {
3473  RWConflict conflict =
3474  dlist_container(RWConflictData, outLink, iter.cur);
3475 
3476  if (isCommit
3478  && SxactIsCommitted(conflict->sxactIn))
3479  {
3484  }
3485 
3486  if (!isCommit
3487  || SxactIsCommitted(conflict->sxactIn)
3489  ReleaseRWConflict(conflict);
3490  }
3491 
3492  /*
3493  * Release all inConflicts from committed and read-only transactions. If
3494  * we're rolling back, clear them all.
3495  */
3497  {
3498  RWConflict conflict =
3499  dlist_container(RWConflictData, inLink, iter.cur);
3500 
3501  if (!isCommit
3502  || SxactIsCommitted(conflict->sxactOut)
3503  || SxactIsReadOnly(conflict->sxactOut))
3504  ReleaseRWConflict(conflict);
3505  }
3506 
3507  if (!topLevelIsDeclaredReadOnly)
3508  {
3509  /*
3510  * Remove ourselves from the list of possible conflicts for concurrent
3511  * READ ONLY transactions, flagging them as unsafe if we have a
3512  * conflict out. If any are waiting DEFERRABLE transactions, wake them
3513  * up if they are known safe or known unsafe.
3514  */
3516  {
3517  RWConflict possibleUnsafeConflict =
3518  dlist_container(RWConflictData, outLink, iter.cur);
3519 
3520  roXact = possibleUnsafeConflict->sxactIn;
3521  Assert(MySerializableXact == possibleUnsafeConflict->sxactOut);
3522  Assert(SxactIsReadOnly(roXact));
3523 
3524  /* Mark conflicted if necessary. */
3525  if (isCommit
3526  && MyXactDidWrite
3529  <= roXact->SeqNo.lastCommitBeforeSnapshot))
3530  {
3531  /*
3532  * This releases possibleUnsafeConflict (as well as all other
3533  * possible conflicts for roXact)
3534  */
3535  FlagSxactUnsafe(roXact);
3536  }
3537  else
3538  {
3539  ReleaseRWConflict(possibleUnsafeConflict);
3540 
3541  /*
3542  * If we were the last possible conflict, flag it safe. The
3543  * transaction can now safely release its predicate locks (but
3544  * that transaction's backend has to do that itself).
3545  */
3547  roXact->flags |= SXACT_FLAG_RO_SAFE;
3548  }
3549 
3550  /*
3551  * Wake up the process for a waiting DEFERRABLE transaction if we
3552  * now know it's either safe or conflicted.
3553  */
3554  if (SxactIsDeferrableWaiting(roXact) &&
3555  (SxactIsROUnsafe(roXact) || SxactIsROSafe(roXact)))
3556  ProcSendSignal(roXact->pgprocno);
3557  }
3558  }
3559 
3560  /*
3561  * Check whether it's time to clean up old transactions. This can only be
3562  * done when the last serializable transaction with the oldest xmin among
3563  * serializable transactions completes. We then find the "new oldest"
3564  * xmin and purge any transactions which finished before this transaction
3565  * was launched.
3566  *
3567  * For parallel queries in read-only transactions, it might run twice. We
3568  * only release the reference on the first call.
3569  */
3570  needToClear = false;
3571  if ((partiallyReleasing ||
3575  {
3577  if (--(PredXact->SxactGlobalXminCount) == 0)
3578  {
3580  needToClear = true;
3581  }
3582  }
3583 
3584  LWLockRelease(SerializableXactHashLock);
3585 
3586  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3587 
3588  /* Add this to the list of transactions to check for later cleanup. */
3589  if (isCommit)
3592 
3593  /*
3594  * If we're releasing a RO_SAFE transaction in parallel mode, we'll only
3595  * partially release it. That's necessary because other backends may have
3596  * a reference to it. The leader will release the SERIALIZABLEXACT itself
3597  * at the end of the transaction after workers have stopped running.
3598  */
3599  if (!isCommit)
3601  isReadOnlySafe && IsInParallelMode(),
3602  false);
3603 
3604  LWLockRelease(SerializableFinishedListLock);
3605 
3606  if (needToClear)
3608 
3610 }
static void SetNewSxactGlobalXmin(void)
Definition: predicate.c:3185
#define SxactIsROUnsafe(sxact)
Definition: predicate.c:288
#define SxactIsDeferrableWaiting(sxact)
Definition: predicate.c:286
static void ReleasePredicateLocksLocal(void)
Definition: predicate.c:3613
static void ClearOldPredicateLocks(void)
Definition: predicate.c:3631
static void FlagSxactUnsafe(SERIALIZABLEXACT *sxact)
Definition: predicate.c:695
#define SxactIsOnFinishedList(sxact)
Definition: predicate.c:263
#define SxactIsROSafe(sxact)
Definition: predicate.c:287
static void ReleaseRWConflict(RWConflict conflict)
Definition: predicate.c:687
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize)
Definition: predicate.c:3769
#define SxactIsRolledBack(sxact)
Definition: predicate.c:275
static SERIALIZABLEXACT * SavedSerializableXact
Definition: predicate.c:427
#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:1809
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:1069

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, VariableCacheData::nextXid, SERIALIZABLEXACT::outConflicts, ParallelContextActive(), SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, PredXact, SERIALIZABLEXACT::prepareSeqNo, ProcSendSignal(), ReleaseOneSerializableXact(), ReleasePredicateLocksLocal(), ReleaseRWConflict(), SavedSerializableXact, SERIALIZABLEXACT::SeqNo, SetNewSxactGlobalXmin(), ShmemVariableCache, 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 1656 of file predicate.c.

1659 {
1661 
1662  /*
1663  * If this is called by parallel.c in a parallel worker, we don't want to
1664  * create a SERIALIZABLEXACT just yet because the leader's
1665  * SERIALIZABLEXACT will be installed with AttachSerializableXact(). We
1666  * also don't want to reject SERIALIZABLE READ ONLY DEFERRABLE in this
1667  * case, because the leader has already determined that the snapshot it
1668  * has passed us is safe. So there is nothing for us to do.
1669  */
1670  if (IsParallelWorker())
1671  return;
1672 
1673  /*
1674  * We do not allow SERIALIZABLE READ ONLY DEFERRABLE transactions to
1675  * import snapshots, since there's no way to wait for a safe snapshot when
1676  * we're using the snap we're told to. (XXX instead of throwing an error,
1677  * we could just ignore the XactDeferrable flag?)
1678  */
1680  ereport(ERROR,
1681  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1682  errmsg("a snapshot-importing transaction must not be READ ONLY DEFERRABLE")));
1683 
1684  (void) GetSerializableTransactionSnapshotInt(snapshot, sourcevxid,
1685  sourcepid);
1686 }

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

Referenced by SetTransactionSnapshot().

◆ ShareSerializableXact()

SerializableXactHandle ShareSerializableXact ( void  )

Definition at line 4980 of file predicate.c.

4981 {
4982  return MySerializableXact;
4983 }

References MySerializableXact.

Referenced by InitializeParallelDSM().

◆ TransferPredicateLocksToHeapRelation()

void TransferPredicateLocksToHeapRelation ( Relation  relation)

Definition at line 3057 of file predicate.c.

3058 {
3059  DropAllPredicateLocksFromTable(relation, true);
3060 }
static void DropAllPredicateLocksFromTable(Relation relation, bool transfer)
Definition: predicate.c:2871

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

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_relation

PGDLLIMPORT int max_predicate_locks_per_relation
extern

Definition at line 368 of file predicate.c.

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_xact

PGDLLIMPORT int max_predicate_locks_per_xact
extern

Definition at line 367 of file predicate.c.

Referenced by CreateLocalPredicateLockHash(), and MaxPredicateChildLocks().