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

4742 {
4743  SERIALIZABLEXACT *sxact;
4744  TwoPhasePredicateRecord record;
4745  TwoPhasePredicateXactRecord *xactRecord;
4746  TwoPhasePredicateLockRecord *lockRecord;
4747  dlist_iter iter;
4748 
4749  sxact = MySerializableXact;
4750  xactRecord = &(record.data.xactRecord);
4751  lockRecord = &(record.data.lockRecord);
4752 
4754  return;
4755 
4756  /* Generate an xact record for our SERIALIZABLEXACT */
4758  xactRecord->xmin = MySerializableXact->xmin;
4759  xactRecord->flags = MySerializableXact->flags;
4760 
4761  /*
4762  * Note that we don't include the list of conflicts in our out in the
4763  * statefile, because new conflicts can be added even after the
4764  * transaction prepares. We'll just make a conservative assumption during
4765  * recovery instead.
4766  */
4767 
4769  &record, sizeof(record));
4770 
4771  /*
4772  * Generate a lock record for each lock.
4773  *
4774  * To do this, we need to walk the predicate lock list in our sxact rather
4775  * than using the local predicate lock table because the latter is not
4776  * guaranteed to be accurate.
4777  */
4778  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4779 
4780  /*
4781  * No need to take sxact->perXactPredicateListLock in parallel mode
4782  * because there cannot be any parallel workers running while we are
4783  * preparing a transaction.
4784  */
4786 
4787  dlist_foreach(iter, &sxact->predicateLocks)
4788  {
4789  PREDICATELOCK *predlock =
4790  dlist_container(PREDICATELOCK, xactLink, iter.cur);
4791 
4793  lockRecord->target = predlock->tag.myTarget->tag;
4794 
4796  &record, sizeof(record));
4797  }
4798 
4799  LWLockRelease(SerializablePredicateListLock);
4800 }
bool ParallelContextActive(void)
Definition: parallel.c:1006
#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:1808
@ 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::@111 data
TwoPhasePredicateLockRecord lockRecord
TwoPhasePredicateXactRecord xactRecord
dlist_node * cur
Definition: ilist.h:179
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1296
#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 5006 of file predicate.c.

5007 {
5008 
5010 
5011  MySerializableXact = (SERIALIZABLEXACT *) handle;
5014 }
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1891

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

Referenced by ParallelWorkerMain().

◆ CheckForSerializableConflictIn()

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

Definition at line 4287 of file predicate.c.

4288 {
4289  PREDICATELOCKTARGETTAG targettag;
4290 
4291  if (!SerializationNeededForWrite(relation))
4292  return;
4293 
4294  /* Check if someone else has already decided that we need to die */
4296  ereport(ERROR,
4298  errmsg("could not serialize access due to read/write dependencies among transactions"),
4299  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4300  errhint("The transaction might succeed if retried.")));
4301 
4302  /*
4303  * We're doing a write which might cause rw-conflicts now or later.
4304  * Memorize that fact.
4305  */
4306  MyXactDidWrite = true;
4307 
4308  /*
4309  * It is important that we check for locks from the finest granularity to
4310  * the coarsest granularity, so that granularity promotion doesn't cause
4311  * us to miss a lock. The new (coarser) lock will be acquired before the
4312  * old (finer) locks are released.
4313  *
4314  * It is not possible to take and hold a lock across the checks for all
4315  * granularities because each target could be in a separate partition.
4316  */
4317  if (tid != NULL)
4318  {
4320  relation->rd_locator.dbOid,
4321  relation->rd_id,
4324  CheckTargetForConflictsIn(&targettag);
4325  }
4326 
4327  if (blkno != InvalidBlockNumber)
4328  {
4330  relation->rd_locator.dbOid,
4331  relation->rd_id,
4332  blkno);
4333  CheckTargetForConflictsIn(&targettag);
4334  }
4335 
4337  relation->rd_locator.dbOid,
4338  relation->rd_id);
4339  CheckTargetForConflictsIn(&targettag);
4340 }
#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:4117
#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 3974 of file predicate.c.

3975 {
3976  SERIALIZABLEXIDTAG sxidtag;
3977  SERIALIZABLEXID *sxid;
3978  SERIALIZABLEXACT *sxact;
3979 
3980  if (!SerializationNeededForRead(relation, snapshot))
3981  return;
3982 
3983  /* Check if someone else has already decided that we need to die */
3985  {
3986  ereport(ERROR,
3988  errmsg("could not serialize access due to read/write dependencies among transactions"),
3989  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
3990  errhint("The transaction might succeed if retried.")));
3991  }
3993 
3995  return;
3996 
3997  /*
3998  * Find sxact or summarized info for the top level xid.
3999  */
4000  sxidtag.xid = xid;
4001  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4002  sxid = (SERIALIZABLEXID *)
4003  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4004  if (!sxid)
4005  {
4006  /*
4007  * Transaction not found in "normal" SSI structures. Check whether it
4008  * got pushed out to SLRU storage for "old committed" transactions.
4009  */
4010  SerCommitSeqNo conflictCommitSeqNo;
4011 
4012  conflictCommitSeqNo = SerialGetMinConflictCommitSeqNo(xid);
4013  if (conflictCommitSeqNo != 0)
4014  {
4015  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4017  || conflictCommitSeqNo
4019  ereport(ERROR,
4021  errmsg("could not serialize access due to read/write dependencies among transactions"),
4022  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4023  errhint("The transaction might succeed if retried.")));
4024 
4027  ereport(ERROR,
4029  errmsg("could not serialize access due to read/write dependencies among transactions"),
4030  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4031  errhint("The transaction might succeed if retried.")));
4032 
4034  }
4035 
4036  /* It's not serializable or otherwise not important. */
4037  LWLockRelease(SerializableXactHashLock);
4038  return;
4039  }
4040  sxact = sxid->myXact;
4041  Assert(TransactionIdEquals(sxact->topXid, xid));
4042  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4043  {
4044  /* Can't conflict with ourself or a transaction that will roll back. */
4045  LWLockRelease(SerializableXactHashLock);
4046  return;
4047  }
4048 
4049  /*
4050  * We have a conflict out to a transaction which has a conflict out to a
4051  * summarized transaction. That summarized transaction must have
4052  * committed first, and we can't tell when it committed in relation to our
4053  * snapshot acquisition, so something needs to be canceled.
4054  */
4055  if (SxactHasSummaryConflictOut(sxact))
4056  {
4057  if (!SxactIsPrepared(sxact))
4058  {
4059  sxact->flags |= SXACT_FLAG_DOOMED;
4060  LWLockRelease(SerializableXactHashLock);
4061  return;
4062  }
4063  else
4064  {
4065  LWLockRelease(SerializableXactHashLock);
4066  ereport(ERROR,
4068  errmsg("could not serialize access due to read/write dependencies among transactions"),
4069  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4070  errhint("The transaction might succeed if retried.")));
4071  }
4072  }
4073 
4074  /*
4075  * If this is a read-only transaction and the writing transaction has
4076  * committed, and it doesn't have a rw-conflict to a transaction which
4077  * committed before it, no conflict.
4078  */
4080  && SxactIsCommitted(sxact)
4081  && !SxactHasSummaryConflictOut(sxact)
4082  && (!SxactHasConflictOut(sxact)
4084  {
4085  /* Read-only transaction will appear to run first. No conflict. */
4086  LWLockRelease(SerializableXactHashLock);
4087  return;
4088  }
4089 
4090  if (!XidIsConcurrent(xid))
4091  {
4092  /* This write was already in our snapshot; no conflict. */
4093  LWLockRelease(SerializableXactHashLock);
4094  return;
4095  }
4096 
4098  {
4099  /* We don't want duplicate conflict records in the list. */
4100  LWLockRelease(SerializableXactHashLock);
4101  return;
4102  }
4103 
4104  /*
4105  * Flag the conflict. But first, if this conflict creates a dangerous
4106  * structure, ereport an error.
4107  */
4109  LWLockRelease(SerializableXactHashLock);
4110 }
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:4452
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:914
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:3923
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:279
#define InvalidSerCommitSeqNo
#define SXACT_FLAG_DOOMED
uint64 SerCommitSeqNo
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
SerCommitSeqNo lastCommitBeforeSnapshot
SerCommitSeqNo earliestOutConflictCommit
union SERIALIZABLEXACT::@110 SeqNo
SERIALIZABLEXACT * myXact
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c: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 3942 of file predicate.c.

3943 {
3944  if (!SerializationNeededForRead(relation, snapshot))
3945  return false;
3946 
3947  /* Check if someone else has already decided that we need to die */
3949  {
3950  ereport(ERROR,
3952  errmsg("could not serialize access due to read/write dependencies among transactions"),
3953  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
3954  errhint("The transaction might succeed if retried.")));
3955  }
3956 
3957  return true;
3958 }

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

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

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

Referenced by CheckPointGuts().

◆ CheckTableForSerializableConflictIn()

void CheckTableForSerializableConflictIn ( Relation  relation)

Definition at line 4370 of file predicate.c.

4371 {
4372  HASH_SEQ_STATUS seqstat;
4373  PREDICATELOCKTARGET *target;
4374  Oid dbId;
4375  Oid heapId;
4376  int i;
4377 
4378  /*
4379  * Bail out quickly if there are no serializable transactions running.
4380  * It's safe to check this without taking locks because the caller is
4381  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4382  * would matter here can be acquired while that is held.
4383  */
4385  return;
4386 
4387  if (!SerializationNeededForWrite(relation))
4388  return;
4389 
4390  /*
4391  * We're doing a write which might cause rw-conflicts now or later.
4392  * Memorize that fact.
4393  */
4394  MyXactDidWrite = true;
4395 
4396  Assert(relation->rd_index == NULL); /* not an index relation */
4397 
4398  dbId = relation->rd_locator.dbOid;
4399  heapId = relation->rd_id;
4400 
4401  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
4402  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4404  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4405 
4406  /* Scan through target list */
4408 
4409  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4410  {
4411  dlist_mutable_iter iter;
4412 
4413  /*
4414  * Check whether this is a target which needs attention.
4415  */
4416  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4417  continue; /* wrong relation id */
4418  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4419  continue; /* wrong database id */
4420 
4421  /*
4422  * Loop through locks for this target and flag conflicts.
4423  */
4424  dlist_foreach_modify(iter, &target->predicateLocks)
4425  {
4426  PREDICATELOCK *predlock =
4427  dlist_container(PREDICATELOCK, targetLink, iter.cur);
4428 
4429  if (predlock->tag.myXact != MySerializableXact
4431  {
4433  }
4434  }
4435  }
4436 
4437  /* Release locks in reverse order */
4438  LWLockRelease(SerializableXactHashLock);
4439  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4441  LWLockRelease(SerializablePredicateListLock);
4442 }
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 1633 of file predicate.c.

1634 {
1636 
1637  /*
1638  * Can't use serializable mode while recovery is still active, as it is,
1639  * for example, on a hot standby. We could get here despite the check in
1640  * check_transaction_isolation() if default_transaction_isolation is set
1641  * to serializable, so phrase the hint accordingly.
1642  */
1643  if (RecoveryInProgress())
1644  ereport(ERROR,
1645  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1646  errmsg("cannot use serializable mode in a hot standby"),
1647  errdetail("default_transaction_isolation is set to \"serializable\"."),
1648  errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1649 
1650  /*
1651  * A special optimization is available for SERIALIZABLE READ ONLY
1652  * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1653  * thereby avoid all SSI overhead once it's running.
1654  */
1656  return GetSafeSnapshot(snapshot);
1657 
1658  return GetSerializableTransactionSnapshotInt(snapshot,
1659  NULL, InvalidPid);
1660 }
int errdetail(const char *fmt,...)
Definition: elog.c:1202
#define InvalidPid
Definition: miscadmin.h:32
static Snapshot GetSafeSnapshot(Snapshot origSnapshot)
Definition: predicate.c:1509
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1715
bool XactDeferrable
Definition: xact.c:85
bool XactReadOnly
Definition: xact.c:82
#define IsolationIsSerializable()
Definition: xact.h:52
bool RecoveryInProgress(void)
Definition: xlog.c:6039

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

1107 {
1108  HASHCTL info;
1109  long max_table_size;
1110  Size requestSize;
1111  bool found;
1112 
1113 #ifndef EXEC_BACKEND
1115 #endif
1116 
1117  /*
1118  * Compute size of predicate lock target hashtable. Note these
1119  * calculations must agree with PredicateLockShmemSize!
1120  */
1121  max_table_size = NPREDICATELOCKTARGETENTS();
1122 
1123  /*
1124  * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1125  * per-predicate-lock-target information.
1126  */
1127  info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1128  info.entrysize = sizeof(PREDICATELOCKTARGET);
1130 
1131  PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1132  max_table_size,
1133  max_table_size,
1134  &info,
1135  HASH_ELEM | HASH_BLOBS |
1137 
1138  /*
1139  * Reserve a dummy entry in the hash table; we use it to make sure there's
1140  * always one entry available when we need to split or combine a page,
1141  * because running out of space there could mean aborting a
1142  * non-serializable transaction.
1143  */
1144  if (!IsUnderPostmaster)
1145  {
1147  HASH_ENTER, &found);
1148  Assert(!found);
1149  }
1150 
1151  /* Pre-calculate the hash and partition lock of the scratch entry */
1154 
1155  /*
1156  * Allocate hash table for PREDICATELOCK structs. This stores per
1157  * xact-lock-of-a-target information.
1158  */
1159  info.keysize = sizeof(PREDICATELOCKTAG);
1160  info.entrysize = sizeof(PREDICATELOCK);
1161  info.hash = predicatelock_hash;
1163 
1164  /* Assume an average of 2 xacts per target */
1165  max_table_size *= 2;
1166 
1167  PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1168  max_table_size,
1169  max_table_size,
1170  &info,
1173 
1174  /*
1175  * Compute size for serializable transaction hashtable. Note these
1176  * calculations must agree with PredicateLockShmemSize!
1177  */
1178  max_table_size = (MaxBackends + max_prepared_xacts);
1179 
1180  /*
1181  * Allocate a list to hold information on transactions participating in
1182  * predicate locking.
1183  *
1184  * Assume an average of 10 predicate locking transactions per backend.
1185  * This allows aggressive cleanup while detail is present before data must
1186  * be summarized for storage in SLRU and the "dummy" transaction.
1187  */
1188  max_table_size *= 10;
1189 
1190  PredXact = ShmemInitStruct("PredXactList",
1192  &found);
1193  Assert(found == IsUnderPostmaster);
1194  if (!found)
1195  {
1196  int i;
1197 
1206  requestSize = mul_size((Size) max_table_size,
1207  sizeof(SERIALIZABLEXACT));
1208  PredXact->element = ShmemAlloc(requestSize);
1209  /* Add all elements to available list, clean. */
1210  memset(PredXact->element, 0, requestSize);
1211  for (i = 0; i < max_table_size; i++)
1212  {
1216  }
1233  }
1234  /* This never changes, so let's keep a local copy. */
1236 
1237  /*
1238  * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1239  * information for serializable transactions which have accessed data.
1240  */
1241  info.keysize = sizeof(SERIALIZABLEXIDTAG);
1242  info.entrysize = sizeof(SERIALIZABLEXID);
1243 
1244  SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1245  max_table_size,
1246  max_table_size,
1247  &info,
1248  HASH_ELEM | HASH_BLOBS |
1249  HASH_FIXED_SIZE);
1250 
1251  /*
1252  * Allocate space for tracking rw-conflicts in lists attached to the
1253  * transactions.
1254  *
1255  * Assume an average of 5 conflicts per transaction. Calculations suggest
1256  * that this will prevent resource exhaustion in even the most pessimal
1257  * loads up to max_connections = 200 with all 200 connections pounding the
1258  * database with serializable transactions. Beyond that, there may be
1259  * occasional transactions canceled when trying to flag conflicts. That's
1260  * probably OK.
1261  */
1262  max_table_size *= 5;
1263 
1264  RWConflictPool = ShmemInitStruct("RWConflictPool",
1266  &found);
1267  Assert(found == IsUnderPostmaster);
1268  if (!found)
1269  {
1270  int i;
1271 
1273  requestSize = mul_size((Size) max_table_size,
1275  RWConflictPool->element = ShmemAlloc(requestSize);
1276  /* Add all elements to available list, clean. */
1277  memset(RWConflictPool->element, 0, requestSize);
1278  for (i = 0; i < max_table_size; i++)
1279  {
1282  }
1283  }
1284 
1285  /*
1286  * Create or attach to the header for the list of finished serializable
1287  * transactions.
1288  */
1290  ShmemInitStruct("FinishedSerializableTransactions",
1291  sizeof(dlist_head),
1292  &found);
1293  Assert(found == IsUnderPostmaster);
1294  if (!found)
1296 
1297  /*
1298  * Initialize the SLRU storage for old committed serializable
1299  * transactions.
1300  */
1301  SerialInit();
1302 }
size_t Size
Definition: c.h:594
bool IsUnderPostmaster
Definition: globals.c:115
int MaxBackends
Definition: globals.c:142
@ 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:1370
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:153
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:388
Size mul_size(Size s1, Size s2)
Definition: shmem.c:511
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:333
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:118

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

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

Definition at line 1959 of file predicate.c.

1960 {
1961  PREDICATELOCKTARGETTAG targettag;
1962  uint32 targettaghash;
1963  LWLock *partitionLock;
1964  PREDICATELOCKTARGET *target;
1965 
1967  relation->rd_locator.dbOid,
1968  relation->rd_id,
1969  blkno);
1970 
1971  targettaghash = PredicateLockTargetTagHashCode(&targettag);
1972  partitionLock = PredicateLockHashPartitionLock(targettaghash);
1973  LWLockAcquire(partitionLock, LW_SHARED);
1974  target = (PREDICATELOCKTARGET *)
1976  &targettag, targettaghash,
1977  HASH_FIND, NULL);
1978  LWLockRelease(partitionLock);
1979 
1980  return (target != NULL);
1981 }
unsigned int uint32
Definition: c.h:495
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 4654 of file predicate.c.

4655 {
4656  dlist_iter near_iter;
4657 
4659  return;
4660 
4662 
4663  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4664 
4665  /*
4666  * Check if someone else has already decided that we need to die. Since
4667  * we set our own DOOMED flag when partially releasing, ignore in that
4668  * case.
4669  */
4672  {
4673  LWLockRelease(SerializableXactHashLock);
4674  ereport(ERROR,
4676  errmsg("could not serialize access due to read/write dependencies among transactions"),
4677  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4678  errhint("The transaction might succeed if retried.")));
4679  }
4680 
4682  {
4683  RWConflict nearConflict =
4684  dlist_container(RWConflictData, inLink, near_iter.cur);
4685 
4686  if (!SxactIsCommitted(nearConflict->sxactOut)
4687  && !SxactIsDoomed(nearConflict->sxactOut))
4688  {
4689  dlist_iter far_iter;
4690 
4691  dlist_foreach(far_iter, &nearConflict->sxactOut->inConflicts)
4692  {
4693  RWConflict farConflict =
4694  dlist_container(RWConflictData, inLink, far_iter.cur);
4695 
4696  if (farConflict->sxactOut == MySerializableXact
4697  || (!SxactIsCommitted(farConflict->sxactOut)
4698  && !SxactIsReadOnly(farConflict->sxactOut)
4699  && !SxactIsDoomed(farConflict->sxactOut)))
4700  {
4701  /*
4702  * Normally, we kill the pivot transaction to make sure we
4703  * make progress if the failing transaction is retried.
4704  * However, we can't kill it if it's already prepared, so
4705  * in that case we commit suicide instead.
4706  */
4707  if (SxactIsPrepared(nearConflict->sxactOut))
4708  {
4709  LWLockRelease(SerializableXactHashLock);
4710  ereport(ERROR,
4712  errmsg("could not serialize access due to read/write dependencies among transactions"),
4713  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4714  errhint("The transaction might succeed if retried.")));
4715  }
4716  nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4717  break;
4718  }
4719  }
4720  }
4721  }
4722 
4725 
4726  LWLockRelease(SerializableXactHashLock);
4727 }
#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 4860 of file predicate.c.

4862 {
4863  TwoPhasePredicateRecord *record;
4864 
4865  Assert(len == sizeof(TwoPhasePredicateRecord));
4866 
4867  record = (TwoPhasePredicateRecord *) recdata;
4868 
4869  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
4870  (record->type == TWOPHASEPREDICATERECORD_LOCK));
4871 
4872  if (record->type == TWOPHASEPREDICATERECORD_XACT)
4873  {
4874  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4875  TwoPhasePredicateXactRecord *xactRecord;
4876  SERIALIZABLEXACT *sxact;
4877  SERIALIZABLEXID *sxid;
4878  SERIALIZABLEXIDTAG sxidtag;
4879  bool found;
4880 
4881  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4882 
4883  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4884  sxact = CreatePredXact();
4885  if (!sxact)
4886  ereport(ERROR,
4887  (errcode(ERRCODE_OUT_OF_MEMORY),
4888  errmsg("out of shared memory")));
4889 
4890  /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
4891  sxact->vxid.backendId = InvalidBackendId;
4893  sxact->pid = 0;
4894  sxact->pgprocno = INVALID_PGPROCNO;
4895 
4896  /* a prepared xact hasn't committed yet */
4900 
4902 
4903  /*
4904  * Don't need to track this; no transactions running at the time the
4905  * recovered xact started are still active, except possibly other
4906  * prepared xacts and we don't care whether those are RO_SAFE or not.
4907  */
4909 
4910  dlist_init(&(sxact->predicateLocks));
4911  dlist_node_init(&sxact->finishedLink);
4912 
4913  sxact->topXid = xid;
4914  sxact->xmin = xactRecord->xmin;
4915  sxact->flags = xactRecord->flags;
4916  Assert(SxactIsPrepared(sxact));
4917  if (!SxactIsReadOnly(sxact))
4918  {
4922  }
4923 
4924  /*
4925  * We don't know whether the transaction had any conflicts or not, so
4926  * we'll conservatively assume that it had both a conflict in and a
4927  * conflict out, and represent that with the summary conflict flags.
4928  */
4929  dlist_init(&(sxact->outConflicts));
4930  dlist_init(&(sxact->inConflicts));
4933 
4934  /* Register the transaction's xid */
4935  sxidtag.xid = xid;
4937  &sxidtag,
4938  HASH_ENTER, &found);
4939  Assert(sxid != NULL);
4940  Assert(!found);
4941  sxid->myXact = (SERIALIZABLEXACT *) sxact;
4942 
4943  /*
4944  * Update global xmin. Note that this is a special case compared to
4945  * registering a normal transaction, because the global xmin might go
4946  * backwards. That's OK, because until recovery is over we're not
4947  * going to complete any transactions or create any non-prepared
4948  * transactions, so there's no danger of throwing away.
4949  */
4952  {
4953  PredXact->SxactGlobalXmin = sxact->xmin;
4955  SerialSetActiveSerXmin(sxact->xmin);
4956  }
4957  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
4958  {
4961  }
4962 
4963  LWLockRelease(SerializableXactHashLock);
4964  }
4965  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
4966  {
4967  /* Lock record. Recreate the PREDICATELOCK */
4968  TwoPhasePredicateLockRecord *lockRecord;
4969  SERIALIZABLEXID *sxid;
4970  SERIALIZABLEXACT *sxact;
4971  SERIALIZABLEXIDTAG sxidtag;
4972  uint32 targettaghash;
4973 
4974  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
4975  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
4976 
4977  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4978  sxidtag.xid = xid;
4979  sxid = (SERIALIZABLEXID *)
4980  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4981  LWLockRelease(SerializableXactHashLock);
4982 
4983  Assert(sxid != NULL);
4984  sxact = sxid->myXact;
4985  Assert(sxact != InvalidSerializableXact);
4986 
4987  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
4988  }
4989 }
#define InvalidBackendId
Definition: backendid.h:23
uint32 LocalTransactionId
Definition: c.h:643
const void size_t len
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2404
static void SerialSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:955
#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 2550 of file predicate.c.

2551 {
2553 
2554  if (!SerializationNeededForRead(relation, snapshot))
2555  return;
2556 
2558  relation->rd_locator.dbOid,
2559  relation->rd_id,
2560  blkno);
2561  PredicateLockAcquire(&tag);
2562 }
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2468

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

3182 {
3183  /*
3184  * Page combines differ from page splits in that we ought to be able to
3185  * remove the locks on the old page after transferring them to the new
3186  * page, instead of duplicating them. However, because we can't edit other
3187  * backends' local lock tables, removing the old lock would leave them
3188  * with an entry in their LocalPredicateLockHash for a lock they're not
3189  * holding, which isn't acceptable. So we wind up having to do the same
3190  * work as a page split, acquiring a lock on the new page and keeping the
3191  * old page locked too. That can lead to some false positives, but should
3192  * be rare in practice.
3193  */
3194  PredicateLockPageSplit(relation, oldblkno, newblkno);
3195 }
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3095

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

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

Definition at line 3095 of file predicate.c.

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

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

2528 {
2530 
2531  if (!SerializationNeededForRead(relation, snapshot))
2532  return;
2533 
2535  relation->rd_locator.dbOid,
2536  relation->rd_id);
2537  PredicateLockAcquire(&tag);
2538 }

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

1309 {
1310  Size size = 0;
1311  long max_table_size;
1312 
1313  /* predicate lock target hash table */
1314  max_table_size = NPREDICATELOCKTARGETENTS();
1315  size = add_size(size, hash_estimate_size(max_table_size,
1316  sizeof(PREDICATELOCKTARGET)));
1317 
1318  /* predicate lock hash table */
1319  max_table_size *= 2;
1320  size = add_size(size, hash_estimate_size(max_table_size,
1321  sizeof(PREDICATELOCK)));
1322 
1323  /*
1324  * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
1325  * margin.
1326  */
1327  size = add_size(size, size / 10);
1328 
1329  /* transaction list */
1330  max_table_size = MaxBackends + max_prepared_xacts;
1331  max_table_size *= 10;
1332  size = add_size(size, PredXactListDataSize);
1333  size = add_size(size, mul_size((Size) max_table_size,
1334  sizeof(SERIALIZABLEXACT)));
1335 
1336  /* transaction xid table */
1337  size = add_size(size, hash_estimate_size(max_table_size,
1338  sizeof(SERIALIZABLEXID)));
1339 
1340  /* rw-conflict pool */
1341  max_table_size *= 5;
1342  size = add_size(size, RWConflictPoolHeaderDataSize);
1343  size = add_size(size, mul_size((Size) max_table_size,
1345 
1346  /* Head for list of finished serializable transactions. */
1347  size = add_size(size, sizeof(dlist_head));
1348 
1349  /* Shared memory structures for SLRU tracking of old committed xids. */
1350  size = add_size(size, sizeof(SerialControlData));
1352 
1353  return size;
1354 }
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:494
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:182

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

2574 {
2576 
2577  if (!SerializationNeededForRead(relation, snapshot))
2578  return;
2579 
2580  /*
2581  * Return if this xact wrote it.
2582  */
2583  if (relation->rd_index == NULL)
2584  {
2585  /* If we wrote it; we already have a write lock. */
2586  if (TransactionIdIsCurrentTransactionId(tuple_xid))
2587  return;
2588  }
2589 
2590  /*
2591  * Do quick-but-not-definitive test for a relation lock first. This will
2592  * never cause a return when the relation is *not* locked, but will
2593  * occasionally let the check continue when there really *is* a relation
2594  * level lock.
2595  */
2597  relation->rd_locator.dbOid,
2598  relation->rd_id);
2599  if (PredicateLockExists(&tag))
2600  return;
2601 
2603  relation->rd_locator.dbOid,
2604  relation->rd_id,
2607  PredicateLockAcquire(&tag);
2608 }
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:1996
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 4833 of file predicate.c.

4834 {
4835  SERIALIZABLEXID *sxid;
4836  SERIALIZABLEXIDTAG sxidtag;
4837 
4838  sxidtag.xid = xid;
4839 
4840  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4841  sxid = (SERIALIZABLEXID *)
4842  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4843  LWLockRelease(SerializableXactHashLock);
4844 
4845  /* xid will not be found if it wasn't a serializable transaction */
4846  if (sxid == NULL)
4847  return;
4848 
4849  /* Release its locks */
4850  MySerializableXact = sxid->myXact;
4851  MyXactDidWrite = true; /* conservatively assume that we wrote
4852  * something */
4853  ReleasePredicateLocks(isCommit, false);
4854 }
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3263

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

1911 {
1912  SERIALIZABLEXIDTAG sxidtag;
1913  SERIALIZABLEXID *sxid;
1914  bool found;
1915 
1916  /*
1917  * If we're not tracking predicate lock data for this transaction, we
1918  * should ignore the request and return quickly.
1919  */
1921  return;
1922 
1923  /* We should have a valid XID and be at the top level. */
1925 
1926  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1927 
1928  /* This should only be done once per transaction. */
1930 
1931  MySerializableXact->topXid = xid;
1932 
1933  sxidtag.xid = xid;
1935  &sxidtag,
1936  HASH_ENTER, &found);
1937  Assert(!found);
1938 
1939  /* Initialize the structure. */
1940  sxid->myXact = MySerializableXact;
1941  LWLockRelease(SerializableXactHashLock);
1942 }

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

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

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

◆ SetSerializableTransactionSnapshot()

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

Definition at line 1673 of file predicate.c.

1676 {
1678 
1679  /*
1680  * If this is called by parallel.c in a parallel worker, we don't want to
1681  * create a SERIALIZABLEXACT just yet because the leader's
1682  * SERIALIZABLEXACT will be installed with AttachSerializableXact(). We
1683  * also don't want to reject SERIALIZABLE READ ONLY DEFERRABLE in this
1684  * case, because the leader has already determined that the snapshot it
1685  * has passed us is safe. So there is nothing for us to do.
1686  */
1687  if (IsParallelWorker())
1688  return;
1689 
1690  /*
1691  * We do not allow SERIALIZABLE READ ONLY DEFERRABLE transactions to
1692  * import snapshots, since there's no way to wait for a safe snapshot when
1693  * we're using the snap we're told to. (XXX instead of throwing an error,
1694  * we could just ignore the XactDeferrable flag?)
1695  */
1697  ereport(ERROR,
1698  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1699  errmsg("a snapshot-importing transaction must not be READ ONLY DEFERRABLE")));
1700 
1701  (void) GetSerializableTransactionSnapshotInt(snapshot, sourcevxid,
1702  sourcepid);
1703 }

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

Referenced by SetTransactionSnapshot().

◆ ShareSerializableXact()

SerializableXactHandle ShareSerializableXact ( void  )

Definition at line 4997 of file predicate.c.

4998 {
4999  return MySerializableXact;
5000 }

References MySerializableXact.

Referenced by InitializeParallelDSM().

◆ TransferPredicateLocksToHeapRelation()

void TransferPredicateLocksToHeapRelation ( Relation  relation)

Definition at line 3074 of file predicate.c.

3075 {
3076  DropAllPredicateLocksFromTable(relation, true);
3077 }
static void DropAllPredicateLocksFromTable(Relation relation, bool transfer)
Definition: predicate.c:2888

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