PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
predicate.h File Reference
#include "storage/itemptr.h"
#include "storage/lock.h"
#include "utils/relcache.h"
#include "utils/snapshot.h"
Include dependency graph for predicate.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef void * SerializableXactHandle
 

Functions

void PredicateLockShmemInit (void)
 
Size PredicateLockShmemSize (void)
 
void CheckPointPredicate (void)
 
bool PageIsPredicateLocked (Relation relation, BlockNumber blkno)
 
Snapshot GetSerializableTransactionSnapshot (Snapshot snapshot)
 
void SetSerializableTransactionSnapshot (Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
 
void RegisterPredicateLockingXid (TransactionId xid)
 
void PredicateLockRelation (Relation relation, Snapshot snapshot)
 
void PredicateLockPage (Relation relation, BlockNumber blkno, Snapshot snapshot)
 
void PredicateLockTID (Relation relation, ItemPointer tid, Snapshot snapshot, TransactionId tuple_xid)
 
void PredicateLockPageSplit (Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
 
void PredicateLockPageCombine (Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
 
void TransferPredicateLocksToHeapRelation (Relation relation)
 
void ReleasePredicateLocks (bool isCommit, bool isReadOnlySafe)
 
bool CheckForSerializableConflictOutNeeded (Relation relation, Snapshot snapshot)
 
void CheckForSerializableConflictOut (Relation relation, TransactionId xid, Snapshot snapshot)
 
void CheckForSerializableConflictIn (Relation relation, ItemPointer tid, BlockNumber blkno)
 
void CheckTableForSerializableConflictIn (Relation relation)
 
void PreCommit_CheckForSerializationFailure (void)
 
void AtPrepare_PredicateLocks (void)
 
void PostPrepare_PredicateLocks (TransactionId xid)
 
void PredicateLockTwoPhaseFinish (TransactionId xid, bool isCommit)
 
void predicatelock_twophase_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
SerializableXactHandle ShareSerializableXact (void)
 
void AttachSerializableXact (SerializableXactHandle handle)
 

Variables

PGDLLIMPORT int max_predicate_locks_per_xact
 
PGDLLIMPORT int max_predicate_locks_per_relation
 
PGDLLIMPORT int max_predicate_locks_per_page
 

Typedef Documentation

◆ SerializableXactHandle

typedef void* SerializableXactHandle

Definition at line 34 of file predicate.h.

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4790 of file predicate.c.

4791{
4792 SERIALIZABLEXACT *sxact;
4794 TwoPhasePredicateXactRecord *xactRecord;
4795 TwoPhasePredicateLockRecord *lockRecord;
4796 dlist_iter iter;
4797
4798 sxact = MySerializableXact;
4799 xactRecord = &(record.data.xactRecord);
4800 lockRecord = &(record.data.lockRecord);
4801
4803 return;
4804
4805 /* Generate an xact record for our SERIALIZABLEXACT */
4807 xactRecord->xmin = MySerializableXact->xmin;
4808 xactRecord->flags = MySerializableXact->flags;
4809
4810 /*
4811 * Note that we don't include the list of conflicts in our out in the
4812 * statefile, because new conflicts can be added even after the
4813 * transaction prepares. We'll just make a conservative assumption during
4814 * recovery instead.
4815 */
4816
4818 &record, sizeof(record));
4819
4820 /*
4821 * Generate a lock record for each lock.
4822 *
4823 * To do this, we need to walk the predicate lock list in our sxact rather
4824 * than using the local predicate lock table because the latter is not
4825 * guaranteed to be accurate.
4826 */
4827 LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4828
4829 /*
4830 * No need to take sxact->perXactPredicateListLock in parallel mode
4831 * because there cannot be any parallel workers running while we are
4832 * preparing a transaction.
4833 */
4835
4836 dlist_foreach(iter, &sxact->predicateLocks)
4837 {
4838 PREDICATELOCK *predlock =
4839 dlist_container(PREDICATELOCK, xactLink, iter.cur);
4840
4842 lockRecord->target = predlock->tag.myTarget->tag;
4843
4845 &record, sizeof(record));
4846 }
4847
4848 LWLockRelease(SerializablePredicateListLock);
4849}
bool ParallelContextActive(void)
Definition: parallel.c:1024
Assert(PointerIsAligned(start, uint64))
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
#define IsParallelWorker()
Definition: parallel.h:60
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1182
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1902
@ LW_SHARED
Definition: lwlock.h:115
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:421
@ TWOPHASEPREDICATERECORD_XACT
@ TWOPHASEPREDICATERECORD_LOCK
#define InvalidSerializableXact
PREDICATELOCKTARGET * myTarget
PREDICATELOCKTARGETTAG tag
PREDICATELOCKTAG tag
PREDICATELOCKTARGETTAG target
TwoPhasePredicateRecordType type
TwoPhasePredicateLockRecord lockRecord
union TwoPhasePredicateRecord::@126 data
TwoPhasePredicateXactRecord xactRecord
dlist_node * cur
Definition: ilist.h:179
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1264
#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 5055 of file predicate.c.

5056{
5057
5059
5063}
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1940

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

Referenced by ParallelWorkerMain().

◆ CheckForSerializableConflictIn()

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

Definition at line 4336 of file predicate.c.

4337{
4338 PREDICATELOCKTARGETTAG targettag;
4339
4340 if (!SerializationNeededForWrite(relation))
4341 return;
4342
4343 /* Check if someone else has already decided that we need to die */
4345 ereport(ERROR,
4347 errmsg("could not serialize access due to read/write dependencies among transactions"),
4348 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4349 errhint("The transaction might succeed if retried.")));
4350
4351 /*
4352 * We're doing a write which might cause rw-conflicts now or later.
4353 * Memorize that fact.
4354 */
4355 MyXactDidWrite = true;
4356
4357 /*
4358 * It is important that we check for locks from the finest granularity to
4359 * the coarsest granularity, so that granularity promotion doesn't cause
4360 * us to miss a lock. The new (coarser) lock will be acquired before the
4361 * old (finer) locks are released.
4362 *
4363 * It is not possible to take and hold a lock across the checks for all
4364 * granularities because each target could be in a separate partition.
4365 */
4366 if (tid != NULL)
4367 {
4369 relation->rd_locator.dbOid,
4370 relation->rd_id,
4373 CheckTargetForConflictsIn(&targettag);
4374 }
4375
4376 if (blkno != InvalidBlockNumber)
4377 {
4379 relation->rd_locator.dbOid,
4380 relation->rd_id,
4381 blkno);
4382 CheckTargetForConflictsIn(&targettag);
4383 }
4384
4386 relation->rd_locator.dbOid,
4387 relation->rd_id);
4388 CheckTargetForConflictsIn(&targettag);
4389}
#define InvalidBlockNumber
Definition: block.h:33
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1231
int errhint(const char *fmt,...)
Definition: elog.c:1318
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#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:77
static bool MyXactDidWrite
Definition: predicate.c:422
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:560
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4166
#define SxactIsDoomed(sxact)
Definition: predicate.c:280
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag, dboid, reloid)
#define SET_PREDICATELOCKTARGETTAG_TUPLE(locktag, dboid, reloid, blocknum, offnum)
Oid rd_id
Definition: rel.h:113
RelFileLocator rd_locator
Definition: rel.h:57

References CheckTargetForConflictsIn(), RelFileLocator::dbOid, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, InvalidBlockNumber, ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), MySerializableXact, MyXactDidWrite, RelationData::rd_id, RelationData::rd_locator, SerializationNeededForWrite(), SET_PREDICATELOCKTARGETTAG_PAGE, SET_PREDICATELOCKTARGETTAG_RELATION, SET_PREDICATELOCKTARGETTAG_TUPLE, and SxactIsDoomed.

Referenced by _bt_check_unique(), _bt_doinsert(), _hash_doinsert(), ginEntryInsert(), ginFindLeafPage(), ginHeapTupleFastInsert(), gistinserttuples(), heap_delete(), heap_insert(), heap_multi_insert(), heap_update(), and index_insert().

◆ CheckForSerializableConflictOut()

void CheckForSerializableConflictOut ( Relation  relation,
TransactionId  xid,
Snapshot  snapshot 
)

Definition at line 4023 of file predicate.c.

4024{
4025 SERIALIZABLEXIDTAG sxidtag;
4026 SERIALIZABLEXID *sxid;
4027 SERIALIZABLEXACT *sxact;
4028
4029 if (!SerializationNeededForRead(relation, snapshot))
4030 return;
4031
4032 /* Check if someone else has already decided that we need to die */
4034 {
4035 ereport(ERROR,
4037 errmsg("could not serialize access due to read/write dependencies among transactions"),
4038 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4039 errhint("The transaction might succeed if retried.")));
4040 }
4042
4044 return;
4045
4046 /*
4047 * Find sxact or summarized info for the top level xid.
4048 */
4049 sxidtag.xid = xid;
4050 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4051 sxid = (SERIALIZABLEXID *)
4052 hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4053 if (!sxid)
4054 {
4055 /*
4056 * Transaction not found in "normal" SSI structures. Check whether it
4057 * got pushed out to SLRU storage for "old committed" transactions.
4058 */
4059 SerCommitSeqNo conflictCommitSeqNo;
4060
4061 conflictCommitSeqNo = SerialGetMinConflictCommitSeqNo(xid);
4062 if (conflictCommitSeqNo != 0)
4063 {
4064 if (conflictCommitSeqNo != InvalidSerCommitSeqNo
4066 || conflictCommitSeqNo
4068 ereport(ERROR,
4070 errmsg("could not serialize access due to read/write dependencies among transactions"),
4071 errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
4072 errhint("The transaction might succeed if retried.")));
4073
4076 ereport(ERROR,
4078 errmsg("could not serialize access due to read/write dependencies among transactions"),
4079 errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
4080 errhint("The transaction might succeed if retried.")));
4081
4083 }
4084
4085 /* It's not serializable or otherwise not important. */
4086 LWLockRelease(SerializableXactHashLock);
4087 return;
4088 }
4089 sxact = sxid->myXact;
4090 Assert(TransactionIdEquals(sxact->topXid, xid));
4091 if (sxact == MySerializableXact || SxactIsDoomed(sxact))
4092 {
4093 /* Can't conflict with ourself or a transaction that will roll back. */
4094 LWLockRelease(SerializableXactHashLock);
4095 return;
4096 }
4097
4098 /*
4099 * We have a conflict out to a transaction which has a conflict out to a
4100 * summarized transaction. That summarized transaction must have
4101 * committed first, and we can't tell when it committed in relation to our
4102 * snapshot acquisition, so something needs to be canceled.
4103 */
4104 if (SxactHasSummaryConflictOut(sxact))
4105 {
4106 if (!SxactIsPrepared(sxact))
4107 {
4108 sxact->flags |= SXACT_FLAG_DOOMED;
4109 LWLockRelease(SerializableXactHashLock);
4110 return;
4111 }
4112 else
4113 {
4114 LWLockRelease(SerializableXactHashLock);
4115 ereport(ERROR,
4117 errmsg("could not serialize access due to read/write dependencies among transactions"),
4118 errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4119 errhint("The transaction might succeed if retried.")));
4120 }
4121 }
4122
4123 /*
4124 * If this is a read-only transaction and the writing transaction has
4125 * committed, and it doesn't have a rw-conflict to a transaction which
4126 * committed before it, no conflict.
4127 */
4129 && SxactIsCommitted(sxact)
4131 && (!SxactHasConflictOut(sxact)
4133 {
4134 /* Read-only transaction will appear to run first. No conflict. */
4135 LWLockRelease(SerializableXactHashLock);
4136 return;
4137 }
4138
4139 if (!XidIsConcurrent(xid))
4140 {
4141 /* This write was already in our snapshot; no conflict. */
4142 LWLockRelease(SerializableXactHashLock);
4143 return;
4144 }
4145
4147 {
4148 /* We don't want duplicate conflict records in the list. */
4149 LWLockRelease(SerializableXactHashLock);
4150 return;
4151 }
4152
4153 /*
4154 * Flag the conflict. But first, if this conflict creates a dangerous
4155 * structure, ereport an error.
4156 */
4158 LWLockRelease(SerializableXactHashLock);
4159}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
@ HASH_FIND
Definition: hsearch.h:113
static bool dlist_is_empty(const dlist_head *head)
Definition: ilist.h:336
@ LW_EXCLUSIVE
Definition: lwlock.h:114
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:610
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:516
#define SxactIsCommitted(sxact)
Definition: predicate.c:277
#define SxactIsReadOnly(sxact)
Definition: predicate.c:281
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:282
#define SxactHasConflictOut(sxact)
Definition: predicate.c:289
#define SxactIsPrepared(sxact)
Definition: predicate.c:278
static HTAB * SerializableXidHash
Definition: predicate.c:396
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4501
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:949
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:3972
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:283
#define InvalidSerCommitSeqNo
#define SXACT_FLAG_DOOMED
uint64 SerCommitSeqNo
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
SerCommitSeqNo lastCommitBeforeSnapshot
union SERIALIZABLEXACT::@125 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:441

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

3992{
3993 if (!SerializationNeededForRead(relation, snapshot))
3994 return false;
3995
3996 /* Check if someone else has already decided that we need to die */
3998 {
3999 ereport(ERROR,
4001 errmsg("could not serialize access due to read/write dependencies among transactions"),
4002 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
4003 errhint("The transaction might succeed if retried.")));
4004 }
4005
4006 return true;
4007}

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

Referenced by heap_prepare_pagescan(), and HeapCheckForSerializableConflictOut().

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 1041 of file predicate.c.

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

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

Referenced by CheckPointGuts().

◆ CheckTableForSerializableConflictIn()

void CheckTableForSerializableConflictIn ( Relation  relation)

Definition at line 4419 of file predicate.c.

4420{
4421 HASH_SEQ_STATUS seqstat;
4422 PREDICATELOCKTARGET *target;
4423 Oid dbId;
4424 Oid heapId;
4425 int i;
4426
4427 /*
4428 * Bail out quickly if there are no serializable transactions running.
4429 * It's safe to check this without taking locks because the caller is
4430 * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4431 * would matter here can be acquired while that is held.
4432 */
4434 return;
4435
4436 if (!SerializationNeededForWrite(relation))
4437 return;
4438
4439 /*
4440 * We're doing a write which might cause rw-conflicts now or later.
4441 * Memorize that fact.
4442 */
4443 MyXactDidWrite = true;
4444
4445 Assert(relation->rd_index == NULL); /* not an index relation */
4446
4447 dbId = relation->rd_locator.dbOid;
4448 heapId = relation->rd_id;
4449
4450 LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
4451 for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4453 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4454
4455 /* Scan through target list */
4457
4458 while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4459 {
4460 dlist_mutable_iter iter;
4461
4462 /*
4463 * Check whether this is a target which needs attention.
4464 */
4465 if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4466 continue; /* wrong relation id */
4467 if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4468 continue; /* wrong database id */
4469
4470 /*
4471 * Loop through locks for this target and flag conflicts.
4472 */
4473 dlist_foreach_modify(iter, &target->predicateLocks)
4474 {
4475 PREDICATELOCK *predlock =
4476 dlist_container(PREDICATELOCK, targetLink, iter.cur);
4477
4478 if (predlock->tag.myXact != MySerializableXact
4480 {
4482 }
4483 }
4484 }
4485
4486 /* Release locks in reverse order */
4487 LWLockRelease(SerializableXactHashLock);
4488 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4490 LWLockRelease(SerializablePredicateListLock);
4491}
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1420
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
#define dlist_foreach_modify(iter, lhead)
Definition: ilist.h:640
int i
Definition: isn.c:77
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:101
unsigned int Oid
Definition: postgres_ext.h:30
static PredXactList PredXact
Definition: predicate.c:384
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:261
static HTAB * PredicateLockTargetHash
Definition: predicate.c:397
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
SERIALIZABLEXACT * myXact
TransactionId SxactGlobalXmin
Form_pg_index rd_index
Definition: rel.h:192
dlist_node * cur
Definition: ilist.h:200

References Assert(), dlist_mutable_iter::cur, RelFileLocator::dbOid, dlist_container, dlist_foreach_modify, FlagRWConflict(), GET_PREDICATELOCKTARGETTAG_DB, GET_PREDICATELOCKTARGETTAG_RELATION, hash_seq_init(), hash_seq_search(), i, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myXact, MyXactDidWrite, NUM_PREDICATELOCK_PARTITIONS, PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredXact, RelationData::rd_id, RelationData::rd_index, RelationData::rd_locator, RWConflictExists(), SerializationNeededForWrite(), PredXactListData::SxactGlobalXmin, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, and TransactionIdIsValid.

Referenced by ExecuteTruncateGuts(), and heap_drop_with_catalog().

◆ GetSerializableTransactionSnapshot()

Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot)

Definition at line 1682 of file predicate.c.

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

References Assert(), ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, GetSafeSnapshot(), GetSerializableTransactionSnapshotInt(), InvalidPid, IsolationIsSerializable, RecoveryInProgress(), XactDeferrable, and XactReadOnly.

Referenced by GetTransactionSnapshot().

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

Definition at line 2008 of file predicate.c.

2009{
2010 PREDICATELOCKTARGETTAG targettag;
2011 uint32 targettaghash;
2012 LWLock *partitionLock;
2013 PREDICATELOCKTARGET *target;
2014
2016 relation->rd_locator.dbOid,
2017 relation->rd_id,
2018 blkno);
2019
2020 targettaghash = PredicateLockTargetTagHashCode(&targettag);
2021 partitionLock = PredicateLockHashPartitionLock(targettaghash);
2022 LWLockAcquire(partitionLock, LW_SHARED);
2023 target = (PREDICATELOCKTARGET *)
2025 &targettag, targettaghash,
2026 HASH_FIND, NULL);
2027 LWLockRelease(partitionLock);
2028
2029 return (target != NULL);
2030}
uint32_t uint32
Definition: c.h:502
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:968
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:303
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:258
Definition: lwlock.h:42

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

◆ PostPrepare_PredicateLocks()

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4703 of file predicate.c.

4704{
4705 dlist_iter near_iter;
4706
4708 return;
4709
4711
4712 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4713
4714 /*
4715 * Check if someone else has already decided that we need to die. Since
4716 * we set our own DOOMED flag when partially releasing, ignore in that
4717 * case.
4718 */
4721 {
4722 LWLockRelease(SerializableXactHashLock);
4723 ereport(ERROR,
4725 errmsg("could not serialize access due to read/write dependencies among transactions"),
4726 errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4727 errhint("The transaction might succeed if retried.")));
4728 }
4729
4731 {
4732 RWConflict nearConflict =
4733 dlist_container(RWConflictData, inLink, near_iter.cur);
4734
4735 if (!SxactIsCommitted(nearConflict->sxactOut)
4736 && !SxactIsDoomed(nearConflict->sxactOut))
4737 {
4738 dlist_iter far_iter;
4739
4740 dlist_foreach(far_iter, &nearConflict->sxactOut->inConflicts)
4741 {
4742 RWConflict farConflict =
4743 dlist_container(RWConflictData, inLink, far_iter.cur);
4744
4745 if (farConflict->sxactOut == MySerializableXact
4746 || (!SxactIsCommitted(farConflict->sxactOut)
4747 && !SxactIsReadOnly(farConflict->sxactOut)
4748 && !SxactIsDoomed(farConflict->sxactOut)))
4749 {
4750 /*
4751 * Normally, we kill the pivot transaction to make sure we
4752 * make progress if the failing transaction is retried.
4753 * However, we can't kill it if it's already prepared, so
4754 * in that case we commit suicide instead.
4755 */
4756 if (SxactIsPrepared(nearConflict->sxactOut))
4757 {
4758 LWLockRelease(SerializableXactHashLock);
4759 ereport(ERROR,
4761 errmsg("could not serialize access due to read/write dependencies among transactions"),
4762 errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4763 errhint("The transaction might succeed if retried.")));
4764 }
4765 nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4766 break;
4767 }
4768 }
4769 }
4770 }
4771
4774
4775 LWLockRelease(SerializableXactHashLock);
4776}
#define SxactIsPartiallyReleased(sxact)
Definition: predicate.c:293
#define SXACT_FLAG_PREPARED
SerCommitSeqNo LastSxactCommitSeqNo
SERIALIZABLEXACT * sxactOut
SerCommitSeqNo prepareSeqNo

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

Referenced by CommitTransaction(), and PrepareTransaction().

◆ predicatelock_twophase_recover()

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

Definition at line 4909 of file predicate.c.

4911{
4913
4915
4916 record = (TwoPhasePredicateRecord *) recdata;
4917
4919 (record->type == TWOPHASEPREDICATERECORD_LOCK));
4920
4921 if (record->type == TWOPHASEPREDICATERECORD_XACT)
4922 {
4923 /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4924 TwoPhasePredicateXactRecord *xactRecord;
4925 SERIALIZABLEXACT *sxact;
4926 SERIALIZABLEXID *sxid;
4927 SERIALIZABLEXIDTAG sxidtag;
4928 bool found;
4929
4930 xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4931
4932 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4933 sxact = CreatePredXact();
4934 if (!sxact)
4935 ereport(ERROR,
4936 (errcode(ERRCODE_OUT_OF_MEMORY),
4937 errmsg("out of shared memory")));
4938
4939 /* vxid for a prepared xact is INVALID_PROC_NUMBER/xid; no pid */
4942 sxact->pid = 0;
4944
4945 /* a prepared xact hasn't committed yet */
4949
4951
4952 /*
4953 * Don't need to track this; no transactions running at the time the
4954 * recovered xact started are still active, except possibly other
4955 * prepared xacts and we don't care whether those are RO_SAFE or not.
4956 */
4958
4959 dlist_init(&(sxact->predicateLocks));
4961
4962 sxact->topXid = xid;
4963 sxact->xmin = xactRecord->xmin;
4964 sxact->flags = xactRecord->flags;
4965 Assert(SxactIsPrepared(sxact));
4966 if (!SxactIsReadOnly(sxact))
4967 {
4971 }
4972
4973 /*
4974 * We don't know whether the transaction had any conflicts or not, so
4975 * we'll conservatively assume that it had both a conflict in and a
4976 * conflict out, and represent that with the summary conflict flags.
4977 */
4978 dlist_init(&(sxact->outConflicts));
4979 dlist_init(&(sxact->inConflicts));
4982
4983 /* Register the transaction's xid */
4984 sxidtag.xid = xid;
4986 &sxidtag,
4987 HASH_ENTER, &found);
4988 Assert(sxid != NULL);
4989 Assert(!found);
4990 sxid->myXact = (SERIALIZABLEXACT *) sxact;
4991
4992 /*
4993 * Update global xmin. Note that this is a special case compared to
4994 * registering a normal transaction, because the global xmin might go
4995 * backwards. That's OK, because until recovery is over we're not
4996 * going to complete any transactions or create any non-prepared
4997 * transactions, so there's no danger of throwing away.
4998 */
5001 {
5002 PredXact->SxactGlobalXmin = sxact->xmin;
5005 }
5007 {
5010 }
5011
5012 LWLockRelease(SerializableXactHashLock);
5013 }
5014 else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
5015 {
5016 /* Lock record. Recreate the PREDICATELOCK */
5017 TwoPhasePredicateLockRecord *lockRecord;
5018 SERIALIZABLEXID *sxid;
5019 SERIALIZABLEXACT *sxact;
5020 SERIALIZABLEXIDTAG sxidtag;
5021 uint32 targettaghash;
5022
5023 lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
5024 targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
5025
5026 LWLockAcquire(SerializableXactHashLock, LW_SHARED);
5027 sxidtag.xid = xid;
5028 sxid = (SERIALIZABLEXID *)
5029 hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
5030 LWLockRelease(SerializableXactHashLock);
5031
5032 Assert(sxid != NULL);
5033 sxact = sxid->myXact;
5035
5036 CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5037 }
5038}
uint32 LocalTransactionId
Definition: c.h:625
int MaxBackends
Definition: globals.c:147
@ HASH_ENTER
Definition: hsearch.h:114
static void dlist_init(dlist_head *head)
Definition: ilist.h:314
static void dlist_node_init(dlist_node *node)
Definition: ilist.h:325
const void size_t len
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2453
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:582
static void SerialSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:990
#define SXACT_FLAG_SUMMARY_CONFLICT_IN
#define RecoverySerCommitSeqNo
VirtualTransactionId vxid
dlist_head possibleUnsafeConflicts
SerCommitSeqNo commitSeqNo
TransactionId finishedBefore
LocalTransactionId localTransactionId
Definition: lock.h:63
ProcNumber procNumber
Definition: lock.h:62
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:314
#define InvalidTransactionId
Definition: transam.h:31
int max_prepared_xacts
Definition: twophase.c:115

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

◆ PredicateLockPage()

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

Definition at line 2599 of file predicate.c.

2600{
2602
2603 if (!SerializationNeededForRead(relation, snapshot))
2604 return;
2605
2607 relation->rd_locator.dbOid,
2608 relation->rd_id,
2609 blkno);
2611}
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2517

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

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

◆ PredicateLockPageCombine()

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

Definition at line 3229 of file predicate.c.

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

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

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

Definition at line 3144 of file predicate.c.

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

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 
)

◆ PredicateLockShmemInit()

void PredicateLockShmemInit ( void  )

Definition at line 1145 of file predicate.c.

1146{
1147 HASHCTL info;
1148 long max_table_size;
1149 Size requestSize;
1150 bool found;
1151
1152#ifndef EXEC_BACKEND
1154#endif
1155
1156 /*
1157 * Compute size of predicate lock target hashtable. Note these
1158 * calculations must agree with PredicateLockShmemSize!
1159 */
1160 max_table_size = NPREDICATELOCKTARGETENTS();
1161
1162 /*
1163 * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1164 * per-predicate-lock-target information.
1165 */
1166 info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1167 info.entrysize = sizeof(PREDICATELOCKTARGET);
1169
1170 PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1171 max_table_size,
1172 max_table_size,
1173 &info,
1176
1177 /*
1178 * Reserve a dummy entry in the hash table; we use it to make sure there's
1179 * always one entry available when we need to split or combine a page,
1180 * because running out of space there could mean aborting a
1181 * non-serializable transaction.
1182 */
1183 if (!IsUnderPostmaster)
1184 {
1186 HASH_ENTER, &found);
1187 Assert(!found);
1188 }
1189
1190 /* Pre-calculate the hash and partition lock of the scratch entry */
1193
1194 /*
1195 * Allocate hash table for PREDICATELOCK structs. This stores per
1196 * xact-lock-of-a-target information.
1197 */
1198 info.keysize = sizeof(PREDICATELOCKTAG);
1199 info.entrysize = sizeof(PREDICATELOCK);
1200 info.hash = predicatelock_hash;
1202
1203 /* Assume an average of 2 xacts per target */
1204 max_table_size *= 2;
1205
1206 PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1207 max_table_size,
1208 max_table_size,
1209 &info,
1212
1213 /*
1214 * Compute size for serializable transaction hashtable. Note these
1215 * calculations must agree with PredicateLockShmemSize!
1216 */
1217 max_table_size = (MaxBackends + max_prepared_xacts);
1218
1219 /*
1220 * Allocate a list to hold information on transactions participating in
1221 * predicate locking.
1222 *
1223 * Assume an average of 10 predicate locking transactions per backend.
1224 * This allows aggressive cleanup while detail is present before data must
1225 * be summarized for storage in SLRU and the "dummy" transaction.
1226 */
1227 max_table_size *= 10;
1228
1229 requestSize = add_size(PredXactListDataSize,
1230 (mul_size((Size) max_table_size,
1231 sizeof(SERIALIZABLEXACT))));
1232
1233 PredXact = ShmemInitStruct("PredXactList",
1234 requestSize,
1235 &found);
1236 Assert(found == IsUnderPostmaster);
1237 if (!found)
1238 {
1239 int i;
1240
1241 /* clean everything, both the header and the element */
1242 memset(PredXact, 0, requestSize);
1243
1254 /* Add all elements to available list, clean. */
1255 for (i = 0; i < max_table_size; i++)
1256 {
1260 }
1277 }
1278 /* This never changes, so let's keep a local copy. */
1280
1281 /*
1282 * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1283 * information for serializable transactions which have accessed data.
1284 */
1285 info.keysize = sizeof(SERIALIZABLEXIDTAG);
1286 info.entrysize = sizeof(SERIALIZABLEXID);
1287
1288 SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1289 max_table_size,
1290 max_table_size,
1291 &info,
1294
1295 /*
1296 * Allocate space for tracking rw-conflicts in lists attached to the
1297 * transactions.
1298 *
1299 * Assume an average of 5 conflicts per transaction. Calculations suggest
1300 * that this will prevent resource exhaustion in even the most pessimal
1301 * loads up to max_connections = 200 with all 200 connections pounding the
1302 * database with serializable transactions. Beyond that, there may be
1303 * occasional transactions canceled when trying to flag conflicts. That's
1304 * probably OK.
1305 */
1306 max_table_size *= 5;
1307
1308 requestSize = RWConflictPoolHeaderDataSize +
1309 mul_size((Size) max_table_size,
1311
1312 RWConflictPool = ShmemInitStruct("RWConflictPool",
1313 requestSize,
1314 &found);
1315 Assert(found == IsUnderPostmaster);
1316 if (!found)
1317 {
1318 int i;
1319
1320 /* clean everything, including the elements */
1321 memset(RWConflictPool, 0, requestSize);
1322
1326 /* Add all elements to available list, clean. */
1327 for (i = 0; i < max_table_size; i++)
1328 {
1331 }
1332 }
1333
1334 /*
1335 * Create or attach to the header for the list of finished serializable
1336 * transactions.
1337 */
1339 ShmemInitStruct("FinishedSerializableTransactions",
1340 sizeof(dlist_head),
1341 &found);
1342 Assert(found == IsUnderPostmaster);
1343 if (!found)
1345
1346 /*
1347 * Initialize the SLRU storage for old committed serializable
1348 * transactions.
1349 */
1350 SerialInit();
1351}
size_t Size
Definition: c.h:576
bool IsUnderPostmaster
Definition: globals.c:121
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_FUNCTION
Definition: hsearch.h:98
#define HASH_BLOBS
Definition: hsearch.h:97
#define HASH_FIXED_SIZE
Definition: hsearch.h:105
#define HASH_PARTITION
Definition: hsearch.h:92
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:75
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:721
@ LWTRANCHE_PER_XACT_PREDICATE_LIST
Definition: lwlock.h:207
static HTAB * PredicateLockHash
Definition: predicate.c:398
static LWLock * ScratchPartitionLock
Definition: predicate.c:408
static uint32 ScratchTargetTagHash
Definition: predicate.c:407
static uint32 predicatelock_hash(const void *key, Size keysize)
Definition: predicate.c:1419
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:362
static void SerialInit(void)
Definition: predicate.c:806
static dlist_head * FinishedSerializableTransactions
Definition: predicate.c:399
static const PREDICATELOCKTARGETTAG ScratchTargetTag
Definition: predicate.c:406
#define NPREDICATELOCKTARGETENTS()
Definition: predicate.c:264
static RWConflictPoolHeader RWConflictPool
Definition: predicate.c:390
#define RWConflictDataSize
#define FirstNormalSerCommitSeqNo
struct PREDICATELOCKTAG PREDICATELOCKTAG
#define PredXactListDataSize
#define RWConflictPoolHeaderDataSize
struct SERIALIZABLEXIDTAG SERIALIZABLEXIDTAG
struct PREDICATELOCKTARGET PREDICATELOCKTARGET
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
struct SERIALIZABLEXID SERIALIZABLEXID
struct RWConflictData * RWConflict
#define SXACT_FLAG_COMMITTED
struct PREDICATELOCK PREDICATELOCK
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:332
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
Size keysize
Definition: hsearch.h:75
HashValueFunc hash
Definition: hsearch.h:78
Size entrysize
Definition: hsearch.h:76
long num_partitions
Definition: hsearch.h:68
SERIALIZABLEXACT * element
SerCommitSeqNo CanPartialClearThrough
SERIALIZABLEXACT * OldCommittedSxact
SerCommitSeqNo HavePartialClearedThrough

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

Referenced by CreateOrAttachShmemStructs().

◆ PredicateLockShmemSize()

Size PredicateLockShmemSize ( void  )

Definition at line 1357 of file predicate.c.

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

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

Referenced by CalculateShmemSize().

◆ PredicateLockTID()

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

Definition at line 2621 of file predicate.c.

2623{
2625
2626 if (!SerializationNeededForRead(relation, snapshot))
2627 return;
2628
2629 /*
2630 * Return if this xact wrote it.
2631 */
2632 if (relation->rd_index == NULL)
2633 {
2634 /* If we wrote it; we already have a write lock. */
2636 return;
2637 }
2638
2639 /*
2640 * Do quick-but-not-definitive test for a relation lock first. This will
2641 * never cause a return when the relation is *not* locked, but will
2642 * occasionally let the check continue when there really *is* a relation
2643 * level lock.
2644 */
2646 relation->rd_locator.dbOid,
2647 relation->rd_id);
2648 if (PredicateLockExists(&tag))
2649 return;
2650
2652 relation->rd_locator.dbOid,
2653 relation->rd_id,
2657}
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2045
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:941

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 BitmapHeapScanNextBlock(), heap_fetch(), and heap_hot_search_buffer().

◆ PredicateLockTwoPhaseFinish()

void PredicateLockTwoPhaseFinish ( TransactionId  xid,
bool  isCommit 
)

Definition at line 4882 of file predicate.c.

4883{
4884 SERIALIZABLEXID *sxid;
4885 SERIALIZABLEXIDTAG sxidtag;
4886
4887 sxidtag.xid = xid;
4888
4889 LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4890 sxid = (SERIALIZABLEXID *)
4891 hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
4892 LWLockRelease(SerializableXactHashLock);
4893
4894 /* xid will not be found if it wasn't a serializable transaction */
4895 if (sxid == NULL)
4896 return;
4897
4898 /* Release its locks */
4899 MySerializableXact = sxid->myXact;
4900 MyXactDidWrite = true; /* conservatively assume that we wrote
4901 * something */
4902 ReleasePredicateLocks(isCommit, false);
4903}
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3312

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

1960{
1961 SERIALIZABLEXIDTAG sxidtag;
1962 SERIALIZABLEXID *sxid;
1963 bool found;
1964
1965 /*
1966 * If we're not tracking predicate lock data for this transaction, we
1967 * should ignore the request and return quickly.
1968 */
1970 return;
1971
1972 /* We should have a valid XID and be at the top level. */
1974
1975 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1976
1977 /* This should only be done once per transaction. */
1979
1981
1982 sxidtag.xid = xid;
1984 &sxidtag,
1985 HASH_ENTER, &found);
1986 Assert(!found);
1987
1988 /* Initialize the structure. */
1989 sxid->myXact = MySerializableXact;
1990 LWLockRelease(SerializableXactHashLock);
1991}

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

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

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

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

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

Referenced by SetTransactionSnapshot().

◆ ShareSerializableXact()

SerializableXactHandle ShareSerializableXact ( void  )

Definition at line 5046 of file predicate.c.

5047{
5048 return MySerializableXact;
5049}

References MySerializableXact.

Referenced by InitializeParallelDSM().

◆ TransferPredicateLocksToHeapRelation()

void TransferPredicateLocksToHeapRelation ( Relation  relation)

Definition at line 3123 of file predicate.c.

3124{
3125 DropAllPredicateLocksFromTable(relation, true);
3126}
static void DropAllPredicateLocksFromTable(Relation relation, bool transfer)
Definition: predicate.c:2937

References DropAllPredicateLocksFromTable().

Referenced by ATRewriteTable(), cluster_rel(), index_concurrently_set_dead(), index_drop(), and reindex_index().

Variable Documentation

◆ max_predicate_locks_per_page

PGDLLIMPORT int max_predicate_locks_per_page
extern

Definition at line 373 of file predicate.c.

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_relation

PGDLLIMPORT int max_predicate_locks_per_relation
extern

Definition at line 372 of file predicate.c.

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_xact

PGDLLIMPORT int max_predicate_locks_per_xact
extern

Definition at line 371 of file predicate.c.

Referenced by CreateLocalPredicateLockHash(), and MaxPredicateChildLocks().