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

4693 {
4694  SERIALIZABLEXACT *sxact;
4695  TwoPhasePredicateRecord record;
4696  TwoPhasePredicateXactRecord *xactRecord;
4697  TwoPhasePredicateLockRecord *lockRecord;
4698  dlist_iter iter;
4699 
4700  sxact = MySerializableXact;
4701  xactRecord = &(record.data.xactRecord);
4702  lockRecord = &(record.data.lockRecord);
4703 
4705  return;
4706 
4707  /* Generate an xact record for our SERIALIZABLEXACT */
4709  xactRecord->xmin = MySerializableXact->xmin;
4710  xactRecord->flags = MySerializableXact->flags;
4711 
4712  /*
4713  * Note that we don't include the list of conflicts in our out in the
4714  * statefile, because new conflicts can be added even after the
4715  * transaction prepares. We'll just make a conservative assumption during
4716  * recovery instead.
4717  */
4718 
4720  &record, sizeof(record));
4721 
4722  /*
4723  * Generate a lock record for each lock.
4724  *
4725  * To do this, we need to walk the predicate lock list in our sxact rather
4726  * than using the local predicate lock table because the latter is not
4727  * guaranteed to be accurate.
4728  */
4729  LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4730 
4731  /*
4732  * No need to take sxact->perXactPredicateListLock in parallel mode
4733  * because there cannot be any parallel workers running while we are
4734  * preparing a transaction.
4735  */
4737 
4738  dlist_foreach(iter, &sxact->predicateLocks)
4739  {
4740  PREDICATELOCK *predlock =
4741  dlist_container(PREDICATELOCK, xactLink, iter.cur);
4742 
4744  lockRecord->target = predlock->tag.myTarget->tag;
4745 
4747  &record, sizeof(record));
4748  }
4749 
4750  LWLockRelease(SerializablePredicateListLock);
4751 }
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:116
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::@106 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 4957 of file predicate.c.

4958 {
4959 
4961 
4962  MySerializableXact = (SERIALIZABLEXACT *) handle;
4965 }
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1854

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

Referenced by ParallelWorkerMain().

◆ CheckForSerializableConflictIn()

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

Definition at line 4242 of file predicate.c.

4243 {
4244  PREDICATELOCKTARGETTAG targettag;
4245 
4246  if (!SerializationNeededForWrite(relation))
4247  return;
4248 
4249  /* Check if someone else has already decided that we need to die */
4251  ereport(ERROR,
4253  errmsg("could not serialize access due to read/write dependencies among transactions"),
4254  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4255  errhint("The transaction might succeed if retried.")));
4256 
4257  /*
4258  * We're doing a write which might cause rw-conflicts now or later.
4259  * Memorize that fact.
4260  */
4261  MyXactDidWrite = true;
4262 
4263  /*
4264  * It is important that we check for locks from the finest granularity to
4265  * the coarsest granularity, so that granularity promotion doesn't cause
4266  * us to miss a lock. The new (coarser) lock will be acquired before the
4267  * old (finer) locks are released.
4268  *
4269  * It is not possible to take and hold a lock across the checks for all
4270  * granularities because each target could be in a separate partition.
4271  */
4272  if (tid != NULL)
4273  {
4275  relation->rd_locator.dbOid,
4276  relation->rd_id,
4279  CheckTargetForConflictsIn(&targettag);
4280  }
4281 
4282  if (blkno != InvalidBlockNumber)
4283  {
4285  relation->rd_locator.dbOid,
4286  relation->rd_id,
4287  blkno);
4288  CheckTargetForConflictsIn(&targettag);
4289  }
4290 
4292  relation->rd_locator.dbOid,
4293  relation->rd_id);
4294  CheckTargetForConflictsIn(&targettag);
4295 }
#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:4072
#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:112
RelFileLocator rd_locator
Definition: rel.h:56

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

3930 {
3931  SERIALIZABLEXIDTAG sxidtag;
3932  SERIALIZABLEXID *sxid;
3933  SERIALIZABLEXACT *sxact;
3934 
3935  if (!SerializationNeededForRead(relation, snapshot))
3936  return;
3937 
3938  /* Check if someone else has already decided that we need to die */
3940  {
3941  ereport(ERROR,
3943  errmsg("could not serialize access due to read/write dependencies among transactions"),
3944  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
3945  errhint("The transaction might succeed if retried.")));
3946  }
3948 
3950  return;
3951 
3952  /*
3953  * Find sxact or summarized info for the top level xid.
3954  */
3955  sxidtag.xid = xid;
3956  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3957  sxid = (SERIALIZABLEXID *)
3958  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
3959  if (!sxid)
3960  {
3961  /*
3962  * Transaction not found in "normal" SSI structures. Check whether it
3963  * got pushed out to SLRU storage for "old committed" transactions.
3964  */
3965  SerCommitSeqNo conflictCommitSeqNo;
3966 
3967  conflictCommitSeqNo = SerialGetMinConflictCommitSeqNo(xid);
3968  if (conflictCommitSeqNo != 0)
3969  {
3970  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
3972  || conflictCommitSeqNo
3974  ereport(ERROR,
3976  errmsg("could not serialize access due to read/write dependencies among transactions"),
3977  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
3978  errhint("The transaction might succeed if retried.")));
3979 
3982  ereport(ERROR,
3984  errmsg("could not serialize access due to read/write dependencies among transactions"),
3985  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
3986  errhint("The transaction might succeed if retried.")));
3987 
3989  }
3990 
3991  /* It's not serializable or otherwise not important. */
3992  LWLockRelease(SerializableXactHashLock);
3993  return;
3994  }
3995  sxact = sxid->myXact;
3996  Assert(TransactionIdEquals(sxact->topXid, xid));
3997  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
3998  {
3999  /* Can't conflict with ourself or a transaction that will roll back. */
4000  LWLockRelease(SerializableXactHashLock);
4001  return;
4002  }
4003 
4004  /*
4005  * We have a conflict out to a transaction which has a conflict out to a
4006  * summarized transaction. That summarized transaction must have
4007  * committed first, and we can't tell when it committed in relation to our
4008  * snapshot acquisition, so something needs to be canceled.
4009  */
4010  if (SxactHasSummaryConflictOut(sxact))
4011  {
4012  if (!SxactIsPrepared(sxact))
4013  {
4014  sxact->flags |= SXACT_FLAG_DOOMED;
4015  LWLockRelease(SerializableXactHashLock);
4016  return;
4017  }
4018  else
4019  {
4020  LWLockRelease(SerializableXactHashLock);
4021  ereport(ERROR,
4023  errmsg("could not serialize access due to read/write dependencies among transactions"),
4024  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4025  errhint("The transaction might succeed if retried.")));
4026  }
4027  }
4028 
4029  /*
4030  * If this is a read-only transaction and the writing transaction has
4031  * committed, and it doesn't have a rw-conflict to a transaction which
4032  * committed before it, no conflict.
4033  */
4035  && SxactIsCommitted(sxact)
4036  && !SxactHasSummaryConflictOut(sxact)
4037  && (!SxactHasConflictOut(sxact)
4039  {
4040  /* Read-only transaction will appear to run first. No conflict. */
4041  LWLockRelease(SerializableXactHashLock);
4042  return;
4043  }
4044 
4045  if (!XidIsConcurrent(xid))
4046  {
4047  /* This write was already in our snapshot; no conflict. */
4048  LWLockRelease(SerializableXactHashLock);
4049  return;
4050  }
4051 
4053  {
4054  /* We don't want duplicate conflict records in the list. */
4055  LWLockRelease(SerializableXactHashLock);
4056  return;
4057  }
4058 
4059  /*
4060  * Flag the conflict. But first, if this conflict creates a dangerous
4061  * structure, ereport an error.
4062  */
4064  LWLockRelease(SerializableXactHashLock);
4065 }
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:115
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:4407
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:913
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:3878
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:279
#define InvalidSerCommitSeqNo
#define SXACT_FLAG_DOOMED
uint64 SerCommitSeqNo
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
SerCommitSeqNo lastCommitBeforeSnapshot
union SERIALIZABLEXACT::@105 SeqNo
SerCommitSeqNo earliestOutConflictCommit
SERIALIZABLEXACT * myXact
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c: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 3897 of file predicate.c.

3898 {
3899  if (!SerializationNeededForRead(relation, snapshot))
3900  return false;
3901 
3902  /* Check if someone else has already decided that we need to die */
3904  {
3905  ereport(ERROR,
3907  errmsg("could not serialize access due to read/write dependencies among transactions"),
3908  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
3909  errhint("The transaction might succeed if retried.")));
3910  }
3911 
3912  return true;
3913 }

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

4326 {
4327  HASH_SEQ_STATUS seqstat;
4328  PREDICATELOCKTARGET *target;
4329  Oid dbId;
4330  Oid heapId;
4331  int i;
4332 
4333  /*
4334  * Bail out quickly if there are no serializable transactions running.
4335  * It's safe to check this without taking locks because the caller is
4336  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4337  * would matter here can be acquired while that is held.
4338  */
4340  return;
4341 
4342  if (!SerializationNeededForWrite(relation))
4343  return;
4344 
4345  /*
4346  * We're doing a write which might cause rw-conflicts now or later.
4347  * Memorize that fact.
4348  */
4349  MyXactDidWrite = true;
4350 
4351  Assert(relation->rd_index == NULL); /* not an index relation */
4352 
4353  dbId = relation->rd_locator.dbOid;
4354  heapId = relation->rd_id;
4355 
4356  LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
4357  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4359  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4360 
4361  /* Scan through target list */
4363 
4364  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4365  {
4366  dlist_mutable_iter iter;
4367 
4368  /*
4369  * Check whether this is a target which needs attention.
4370  */
4371  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4372  continue; /* wrong relation id */
4373  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4374  continue; /* wrong database id */
4375 
4376  /*
4377  * Loop through locks for this target and flag conflicts.
4378  */
4379  dlist_foreach_modify(iter, &target->predicateLocks)
4380  {
4381  PREDICATELOCK *predlock =
4382  dlist_container(PREDICATELOCK, targetLink, iter.cur);
4383 
4384  if (predlock->tag.myXact != MySerializableXact
4386  {
4388  }
4389  }
4390  }
4391 
4392  /* Release locks in reverse order */
4393  LWLockRelease(SerializableXactHashLock);
4394  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4396  LWLockRelease(SerializablePredicateListLock);
4397 }
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:102
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:188
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 1609 of file predicate.c.

1610 {
1612 
1613  /*
1614  * Can't use serializable mode while recovery is still active, as it is,
1615  * for example, on a hot standby. We could get here despite the check in
1616  * check_transaction_isolation() if default_transaction_isolation is set
1617  * to serializable, so phrase the hint accordingly.
1618  */
1619  if (RecoveryInProgress())
1620  ereport(ERROR,
1621  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1622  errmsg("cannot use serializable mode in a hot standby"),
1623  errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1624  errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1625 
1626  /*
1627  * A special optimization is available for SERIALIZABLE READ ONLY
1628  * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1629  * thereby avoid all SSI overhead once it's running.
1630  */
1632  return GetSafeSnapshot(snapshot);
1633 
1634  return GetSerializableTransactionSnapshotInt(snapshot,
1635  NULL, InvalidPid);
1636 }
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:1691
bool XactDeferrable
Definition: xact.c:85
bool XactReadOnly
Definition: xact.c:82
#define IsolationIsSerializable()
Definition: xact.h:52
bool RecoveryInProgress(void)
Definition: xlog.c:5908

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:203
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 1922 of file predicate.c.

1923 {
1924  PREDICATELOCKTARGETTAG targettag;
1925  uint32 targettaghash;
1926  LWLock *partitionLock;
1927  PREDICATELOCKTARGET *target;
1928 
1930  relation->rd_locator.dbOid,
1931  relation->rd_id,
1932  blkno);
1933 
1934  targettaghash = PredicateLockTargetTagHashCode(&targettag);
1935  partitionLock = PredicateLockHashPartitionLock(targettaghash);
1936  LWLockAcquire(partitionLock, LW_SHARED);
1937  target = (PREDICATELOCKTARGET *)
1939  &targettag, targettaghash,
1940  HASH_FIND, NULL);
1941  LWLockRelease(partitionLock);
1942 
1943  return (target != NULL);
1944 }
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:40

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

4610 {
4611  dlist_iter near_iter;
4612 
4614  return;
4615 
4617 
4618  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4619 
4620  /* Check if someone else has already decided that we need to die */
4622  {
4624  LWLockRelease(SerializableXactHashLock);
4625  ereport(ERROR,
4627  errmsg("could not serialize access due to read/write dependencies among transactions"),
4628  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4629  errhint("The transaction might succeed if retried.")));
4630  }
4631 
4633  {
4634  RWConflict nearConflict =
4635  dlist_container(RWConflictData, inLink, near_iter.cur);
4636 
4637  if (!SxactIsCommitted(nearConflict->sxactOut)
4638  && !SxactIsDoomed(nearConflict->sxactOut))
4639  {
4640  dlist_iter far_iter;
4641 
4642  dlist_foreach(far_iter, &nearConflict->sxactOut->inConflicts)
4643  {
4644  RWConflict farConflict =
4645  dlist_container(RWConflictData, inLink, far_iter.cur);
4646 
4647  if (farConflict->sxactOut == MySerializableXact
4648  || (!SxactIsCommitted(farConflict->sxactOut)
4649  && !SxactIsReadOnly(farConflict->sxactOut)
4650  && !SxactIsDoomed(farConflict->sxactOut)))
4651  {
4652  /*
4653  * Normally, we kill the pivot transaction to make sure we
4654  * make progress if the failing transaction is retried.
4655  * However, we can't kill it if it's already prepared, so
4656  * in that case we commit suicide instead.
4657  */
4658  if (SxactIsPrepared(nearConflict->sxactOut))
4659  {
4660  LWLockRelease(SerializableXactHashLock);
4661  ereport(ERROR,
4663  errmsg("could not serialize access due to read/write dependencies among transactions"),
4664  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4665  errhint("The transaction might succeed if retried.")));
4666  }
4667  nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4668  break;
4669  }
4670  }
4671  }
4672  }
4673 
4676 
4677  LWLockRelease(SerializableXactHashLock);
4678 }
#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 4811 of file predicate.c.

4813 {
4814  TwoPhasePredicateRecord *record;
4815 
4816  Assert(len == sizeof(TwoPhasePredicateRecord));
4817 
4818  record = (TwoPhasePredicateRecord *) recdata;
4819 
4820  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
4821  (record->type == TWOPHASEPREDICATERECORD_LOCK));
4822 
4823  if (record->type == TWOPHASEPREDICATERECORD_XACT)
4824  {
4825  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4826  TwoPhasePredicateXactRecord *xactRecord;
4827  SERIALIZABLEXACT *sxact;
4828  SERIALIZABLEXID *sxid;
4829  SERIALIZABLEXIDTAG sxidtag;
4830  bool found;
4831 
4832  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4833 
4834  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4835  sxact = CreatePredXact();
4836  if (!sxact)
4837  ereport(ERROR,
4838  (errcode(ERRCODE_OUT_OF_MEMORY),
4839  errmsg("out of shared memory")));
4840 
4841  /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
4842  sxact->vxid.backendId = InvalidBackendId;
4844  sxact->pid = 0;
4845  sxact->pgprocno = INVALID_PGPROCNO;
4846 
4847  /* a prepared xact hasn't committed yet */
4851 
4853 
4854  /*
4855  * Don't need to track this; no transactions running at the time the
4856  * recovered xact started are still active, except possibly other
4857  * prepared xacts and we don't care whether those are RO_SAFE or not.
4858  */
4860 
4861  dlist_init(&(sxact->predicateLocks));
4862  dlist_node_init(&sxact->finishedLink);
4863 
4864  sxact->topXid = xid;
4865  sxact->xmin = xactRecord->xmin;
4866  sxact->flags = xactRecord->flags;
4867  Assert(SxactIsPrepared(sxact));
4868  if (!SxactIsReadOnly(sxact))
4869  {
4873  }
4874 
4875  /*
4876  * We don't know whether the transaction had any conflicts or not, so
4877  * we'll conservatively assume that it had both a conflict in and a
4878  * conflict out, and represent that with the summary conflict flags.
4879  */
4880  dlist_init(&(sxact->outConflicts));
4881  dlist_init(&(sxact->inConflicts));
4884 
4885  /* Register the transaction's xid */
4886  sxidtag.xid = xid;
4888  &sxidtag,
4889  HASH_ENTER, &found);
4890  Assert(sxid != NULL);
4891  Assert(!found);
4892  sxid->myXact = (SERIALIZABLEXACT *) sxact;
4893 
4894  /*
4895  * Update global xmin. Note that this is a special case compared to
4896  * registering a normal transaction, because the global xmin might go
4897  * backwards. That's OK, because until recovery is over we're not
4898  * going to complete any transactions or create any non-prepared
4899  * transactions, so there's no danger of throwing away.
4900  */
4903  {
4904  PredXact->SxactGlobalXmin = sxact->xmin;
4906  SerialSetActiveSerXmin(sxact->xmin);
4907  }
4908  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
4909  {
4912  }
4913 
4914  LWLockRelease(SerializableXactHashLock);
4915  }
4916  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
4917  {
4918  /* Lock record. Recreate the PREDICATELOCK */
4919  TwoPhasePredicateLockRecord *lockRecord;
4920  SERIALIZABLEXID *sxid;
4921  SERIALIZABLEXACT *sxact;
4922  SERIALIZABLEXIDTAG sxidtag;
4923  uint32 targettaghash;
4924 
4925  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
4926  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
4927 
4928  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4929  sxidtag.xid = xid;
4930  sxid = (SERIALIZABLEXID *)
4931  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4932  LWLockRelease(SerializableXactHashLock);
4933 
4934  Assert(sxid != NULL);
4935  sxact = sxid->myXact;
4936  Assert(sxact != InvalidSerializableXact);
4937 
4938  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
4939  }
4940 }
#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:2367
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 2513 of file predicate.c.

2514 {
2516 
2517  if (!SerializationNeededForRead(relation, snapshot))
2518  return;
2519 
2521  relation->rd_locator.dbOid,
2522  relation->rd_id,
2523  blkno);
2524  PredicateLockAcquire(&tag);
2525 }
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2431

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

3145 {
3146  /*
3147  * Page combines differ from page splits in that we ought to be able to
3148  * remove the locks on the old page after transferring them to the new
3149  * page, instead of duplicating them. However, because we can't edit other
3150  * backends' local lock tables, removing the old lock would leave them
3151  * with an entry in their LocalPredicateLockHash for a lock they're not
3152  * holding, which isn't acceptable. So we wind up having to do the same
3153  * work as a page split, acquiring a lock on the new page and keeping the
3154  * old page locked too. That can lead to some false positives, but should
3155  * be rare in practice.
3156  */
3157  PredicateLockPageSplit(relation, oldblkno, newblkno);
3158 }
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3058

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

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

Definition at line 3058 of file predicate.c.

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

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

2491 {
2493 
2494  if (!SerializationNeededForRead(relation, snapshot))
2495  return;
2496 
2498  relation->rd_locator.dbOid,
2499  relation->rd_id);
2500  PredicateLockAcquire(&tag);
2501 }

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

2537 {
2539 
2540  if (!SerializationNeededForRead(relation, snapshot))
2541  return;
2542 
2543  /*
2544  * Return if this xact wrote it.
2545  */
2546  if (relation->rd_index == NULL)
2547  {
2548  /* If we wrote it; we already have a write lock. */
2549  if (TransactionIdIsCurrentTransactionId(tuple_xid))
2550  return;
2551  }
2552 
2553  /*
2554  * Do quick-but-not-definitive test for a relation lock first. This will
2555  * never cause a return when the relation is *not* locked, but will
2556  * occasionally let the check continue when there really *is* a relation
2557  * level lock.
2558  */
2560  relation->rd_locator.dbOid,
2561  relation->rd_id);
2562  if (PredicateLockExists(&tag))
2563  return;
2564 
2566  relation->rd_locator.dbOid,
2567  relation->rd_id,
2570  PredicateLockAcquire(&tag);
2571 }
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:1959
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 4784 of file predicate.c.

4785 {
4786  SERIALIZABLEXID *sxid;
4787  SERIALIZABLEXIDTAG sxidtag;
4788 
4789  sxidtag.xid = xid;
4790 
4791  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4792  sxid = (SERIALIZABLEXID *)
4793  hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4794  LWLockRelease(SerializableXactHashLock);
4795 
4796  /* xid will not be found if it wasn't a serializable transaction */
4797  if (sxid == NULL)
4798  return;
4799 
4800  /* Release its locks */
4801  MySerializableXact = sxid->myXact;
4802  MyXactDidWrite = true; /* conservatively assume that we wrote
4803  * something */
4804  ReleasePredicateLocks(isCommit, false);
4805 }
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3226

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

1874 {
1875  SERIALIZABLEXIDTAG sxidtag;
1876  SERIALIZABLEXID *sxid;
1877  bool found;
1878 
1879  /*
1880  * If we're not tracking predicate lock data for this transaction, we
1881  * should ignore the request and return quickly.
1882  */
1884  return;
1885 
1886  /* We should have a valid XID and be at the top level. */
1888 
1889  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1890 
1891  /* This should only be done once per transaction. */
1893 
1894  MySerializableXact->topXid = xid;
1895 
1896  sxidtag.xid = xid;
1898  &sxidtag,
1899  HASH_ENTER, &found);
1900  Assert(!found);
1901 
1902  /* Initialize the structure. */
1903  sxid->myXact = MySerializableXact;
1904  LWLockRelease(SerializableXactHashLock);
1905 }

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

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

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

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

Referenced by SetTransactionSnapshot().

◆ ShareSerializableXact()

SerializableXactHandle ShareSerializableXact ( void  )

Definition at line 4948 of file predicate.c.

4949 {
4950  return MySerializableXact;
4951 }

References MySerializableXact.

Referenced by InitializeParallelDSM().

◆ TransferPredicateLocksToHeapRelation()

void TransferPredicateLocksToHeapRelation ( Relation  relation)

Definition at line 3037 of file predicate.c.

3038 {
3039  DropAllPredicateLocksFromTable(relation, true);
3040 }
static void DropAllPredicateLocksFromTable(Relation relation, bool transfer)
Definition: predicate.c:2851

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