PostgreSQL Source Code git master
predicate.c File Reference
#include "postgres.h"
#include "access/parallel.h"
#include "access/slru.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "port/pg_lfind.h"
#include "storage/predicate.h"
#include "storage/predicate_internals.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/guc_hooks.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
Include dependency graph for predicate.c:

Go to the source code of this file.

Data Structures

struct  SerialControlData
 

Macros

#define TargetTagIsCoveredBy(covered_target, covering_target)
 
#define PredicateLockHashPartition(hashcode)    ((hashcode) % NUM_PREDICATELOCK_PARTITIONS)
 
#define PredicateLockHashPartitionLock(hashcode)
 
#define PredicateLockHashPartitionLockByIndex(i)    (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
 
#define NPREDICATELOCKTARGETENTS()    mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
 
#define SxactIsOnFinishedList(sxact)   (!dlist_node_is_detached(&(sxact)->finishedLink))
 
#define SxactIsCommitted(sxact)   (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)
 
#define SxactIsPrepared(sxact)   (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)
 
#define SxactIsRolledBack(sxact)   (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0)
 
#define SxactIsDoomed(sxact)   (((sxact)->flags & SXACT_FLAG_DOOMED) != 0)
 
#define SxactIsReadOnly(sxact)   (((sxact)->flags & SXACT_FLAG_READ_ONLY) != 0)
 
#define SxactHasSummaryConflictIn(sxact)   (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_IN) != 0)
 
#define SxactHasSummaryConflictOut(sxact)   (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_OUT) != 0)
 
#define SxactHasConflictOut(sxact)   (((sxact)->flags & SXACT_FLAG_CONFLICT_OUT) != 0)
 
#define SxactIsDeferrableWaiting(sxact)   (((sxact)->flags & SXACT_FLAG_DEFERRABLE_WAITING) != 0)
 
#define SxactIsROSafe(sxact)   (((sxact)->flags & SXACT_FLAG_RO_SAFE) != 0)
 
#define SxactIsROUnsafe(sxact)   (((sxact)->flags & SXACT_FLAG_RO_UNSAFE) != 0)
 
#define SxactIsPartiallyReleased(sxact)   (((sxact)->flags & SXACT_FLAG_PARTIALLY_RELEASED) != 0)
 
#define PredicateLockTargetTagHashCode(predicatelocktargettag)    get_hash_value(PredicateLockTargetHash, predicatelocktargettag)
 
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
 
#define SerialSlruCtl   (&SerialSlruCtlData)
 
#define SERIAL_PAGESIZE   BLCKSZ
 
#define SERIAL_ENTRYSIZE   sizeof(SerCommitSeqNo)
 
#define SERIAL_ENTRIESPERPAGE   (SERIAL_PAGESIZE / SERIAL_ENTRYSIZE)
 
#define SERIAL_MAX_PAGE   (MaxTransactionId / SERIAL_ENTRIESPERPAGE)
 
#define SerialNextPage(page)   (((page) >= SERIAL_MAX_PAGE) ? 0 : (page) + 1)
 
#define SerialValue(slotno, xid)
 
#define SerialPage(xid)   (((uint32) (xid)) / SERIAL_ENTRIESPERPAGE)
 

Typedefs

typedef struct SerialControlData SerialControlData
 
typedef struct SerialControlDataSerialControl
 

Functions

static SERIALIZABLEXACTCreatePredXact (void)
 
static void ReleasePredXact (SERIALIZABLEXACT *sxact)
 
static bool RWConflictExists (const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
 
static void SetRWConflict (SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
 
static void SetPossibleUnsafeConflict (SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
 
static void ReleaseRWConflict (RWConflict conflict)
 
static void FlagSxactUnsafe (SERIALIZABLEXACT *sxact)
 
static bool SerialPagePrecedesLogically (int64 page1, int64 page2)
 
static void SerialInit (void)
 
static void SerialAdd (TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
 
static SerCommitSeqNo SerialGetMinConflictCommitSeqNo (TransactionId xid)
 
static void SerialSetActiveSerXmin (TransactionId xid)
 
static uint32 predicatelock_hash (const void *key, Size keysize)
 
static void SummarizeOldestCommittedSxact (void)
 
static Snapshot GetSafeSnapshot (Snapshot origSnapshot)
 
static Snapshot GetSerializableTransactionSnapshotInt (Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
 
static bool PredicateLockExists (const PREDICATELOCKTARGETTAG *targettag)
 
static bool GetParentPredicateLockTag (const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
 
static bool CoarserLockCovers (const PREDICATELOCKTARGETTAG *newtargettag)
 
static void RemoveScratchTarget (bool lockheld)
 
static void RestoreScratchTarget (bool lockheld)
 
static void RemoveTargetIfNoLongerUsed (PREDICATELOCKTARGET *target, uint32 targettaghash)
 
static void DeleteChildTargetLocks (const PREDICATELOCKTARGETTAG *newtargettag)
 
static int MaxPredicateChildLocks (const PREDICATELOCKTARGETTAG *tag)
 
static bool CheckAndPromotePredicateLockRequest (const PREDICATELOCKTARGETTAG *reqtag)
 
static void DecrementParentLocks (const PREDICATELOCKTARGETTAG *targettag)
 
static void CreatePredicateLock (const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
 
static void DeleteLockTarget (PREDICATELOCKTARGET *target, uint32 targettaghash)
 
static bool TransferPredicateLocksToNewTarget (PREDICATELOCKTARGETTAG oldtargettag, PREDICATELOCKTARGETTAG newtargettag, bool removeOld)
 
static void PredicateLockAcquire (const PREDICATELOCKTARGETTAG *targettag)
 
static void DropAllPredicateLocksFromTable (Relation relation, bool transfer)
 
static void SetNewSxactGlobalXmin (void)
 
static void ClearOldPredicateLocks (void)
 
static void ReleaseOneSerializableXact (SERIALIZABLEXACT *sxact, bool partial, bool summarize)
 
static bool XidIsConcurrent (TransactionId xid)
 
static void CheckTargetForConflictsIn (PREDICATELOCKTARGETTAG *targettag)
 
static void FlagRWConflict (SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
 
static void OnConflict_CheckForSerializationFailure (const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
 
static void CreateLocalPredicateLockHash (void)
 
static void ReleasePredicateLocksLocal (void)
 
static bool PredicateLockingNeededForRelation (Relation relation)
 
static bool SerializationNeededForRead (Relation relation, Snapshot snapshot)
 
static bool SerializationNeededForWrite (Relation relation)
 
bool check_serial_buffers (int *newval, void **extra, GucSource source)
 
void CheckPointPredicate (void)
 
void PredicateLockShmemInit (void)
 
Size PredicateLockShmemSize (void)
 
PredicateLockDataGetPredicateLockStatusData (void)
 
int GetSafeSnapshotBlockingPids (int blocked_pid, int *output, int output_size)
 
Snapshot GetSerializableTransactionSnapshot (Snapshot snapshot)
 
void SetSerializableTransactionSnapshot (Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
 
void RegisterPredicateLockingXid (TransactionId xid)
 
bool PageIsPredicateLocked (Relation relation, BlockNumber blkno)
 
void PredicateLockRelation (Relation relation, Snapshot snapshot)
 
void PredicateLockPage (Relation relation, BlockNumber blkno, Snapshot snapshot)
 
void PredicateLockTID (Relation relation, const ItemPointerData *tid, Snapshot snapshot, TransactionId tuple_xid)
 
void TransferPredicateLocksToHeapRelation (Relation relation)
 
void PredicateLockPageSplit (Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
 
void PredicateLockPageCombine (Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
 
void ReleasePredicateLocks (bool isCommit, bool isReadOnlySafe)
 
bool CheckForSerializableConflictOutNeeded (Relation relation, Snapshot snapshot)
 
void CheckForSerializableConflictOut (Relation relation, TransactionId xid, Snapshot snapshot)
 
void CheckForSerializableConflictIn (Relation relation, const ItemPointerData *tid, BlockNumber blkno)
 
void CheckTableForSerializableConflictIn (Relation relation)
 
void PreCommit_CheckForSerializationFailure (void)
 
void AtPrepare_PredicateLocks (void)
 
void PostPrepare_PredicateLocks (FullTransactionId fxid)
 
void PredicateLockTwoPhaseFinish (FullTransactionId fxid, bool isCommit)
 
void predicatelock_twophase_recover (FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
 
SerializableXactHandle ShareSerializableXact (void)
 
void AttachSerializableXact (SerializableXactHandle handle)
 

Variables

static SlruCtlData SerialSlruCtlData
 
static SerialControl serialControl
 
static SERIALIZABLEXACTOldCommittedSxact
 
int max_predicate_locks_per_xact
 
int max_predicate_locks_per_relation
 
int max_predicate_locks_per_page
 
static PredXactList PredXact
 
static RWConflictPoolHeader RWConflictPool
 
static HTABSerializableXidHash
 
static HTABPredicateLockTargetHash
 
static HTABPredicateLockHash
 
static dlist_headFinishedSerializableTransactions
 
static const PREDICATELOCKTARGETTAG ScratchTargetTag = {0, 0, 0, 0}
 
static uint32 ScratchTargetTagHash
 
static LWLockScratchPartitionLock
 
static HTABLocalPredicateLockHash = NULL
 
static SERIALIZABLEXACTMySerializableXact = InvalidSerializableXact
 
static bool MyXactDidWrite = false
 
static SERIALIZABLEXACTSavedSerializableXact = InvalidSerializableXact
 

Macro Definition Documentation

◆ NPREDICATELOCKTARGETENTS

#define NPREDICATELOCKTARGETENTS ( )     mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))

Definition at line 264 of file predicate.c.

◆ PredicateLockHashCodeFromTargetHashCode

#define PredicateLockHashCodeFromTargetHashCode (   predicatelocktag,
  targethash 
)
Value:
((targethash) ^ ((uint32) PointerGetDatum((predicatelocktag)->myXact)) \
uint32_t uint32
Definition: c.h:552
#define LOG2_NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:98
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332

Definition at line 316 of file predicate.c.

◆ PredicateLockHashPartition

#define PredicateLockHashPartition (   hashcode)     ((hashcode) % NUM_PREDICATELOCK_PARTITIONS)

Definition at line 256 of file predicate.c.

◆ PredicateLockHashPartitionLock

#define PredicateLockHashPartitionLock (   hashcode)
Value:
PredicateLockHashPartition(hashcode)].lock)
LWLockPadded * MainLWLockArray
Definition: lwlock.c:161
#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET
Definition: lwlock.h:105
LWLock lock
Definition: lwlock.h:70

Definition at line 258 of file predicate.c.

◆ PredicateLockHashPartitionLockByIndex

#define PredicateLockHashPartitionLockByIndex (   i)     (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)

Definition at line 261 of file predicate.c.

◆ PredicateLockTargetTagHashCode

#define PredicateLockTargetTagHashCode (   predicatelocktargettag)     get_hash_value(PredicateLockTargetHash, predicatelocktargettag)

Definition at line 303 of file predicate.c.

◆ SERIAL_ENTRIESPERPAGE

#define SERIAL_ENTRIESPERPAGE   (SERIAL_PAGESIZE / SERIAL_ENTRYSIZE)

Definition at line 330 of file predicate.c.

◆ SERIAL_ENTRYSIZE

#define SERIAL_ENTRYSIZE   sizeof(SerCommitSeqNo)

Definition at line 329 of file predicate.c.

◆ SERIAL_MAX_PAGE

#define SERIAL_MAX_PAGE   (MaxTransactionId / SERIAL_ENTRIESPERPAGE)

Definition at line 335 of file predicate.c.

◆ SERIAL_PAGESIZE

#define SERIAL_PAGESIZE   BLCKSZ

Definition at line 328 of file predicate.c.

◆ SerialNextPage

#define SerialNextPage (   page)    (((page) >= SERIAL_MAX_PAGE) ? 0 : (page) + 1)

Definition at line 337 of file predicate.c.

◆ SerialPage

#define SerialPage (   xid)    (((uint32) (xid)) / SERIAL_ENTRIESPERPAGE)

Definition at line 343 of file predicate.c.

◆ SerialSlruCtl

#define SerialSlruCtl   (&SerialSlruCtlData)

Definition at line 326 of file predicate.c.

◆ SerialValue

#define SerialValue (   slotno,
  xid 
)
Value:
(*((SerCommitSeqNo *) \
(SerialSlruCtl->shared->page_buffer[slotno] + \
#define SERIAL_ENTRYSIZE
Definition: predicate.c:329
#define SERIAL_ENTRIESPERPAGE
Definition: predicate.c:330
#define SerialSlruCtl
Definition: predicate.c:326
uint64 SerCommitSeqNo

Definition at line 339 of file predicate.c.

◆ SxactHasConflictOut

#define SxactHasConflictOut (   sxact)    (((sxact)->flags & SXACT_FLAG_CONFLICT_OUT) != 0)

Definition at line 289 of file predicate.c.

◆ SxactHasSummaryConflictIn

#define SxactHasSummaryConflictIn (   sxact)    (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_IN) != 0)

Definition at line 282 of file predicate.c.

◆ SxactHasSummaryConflictOut

#define SxactHasSummaryConflictOut (   sxact)    (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_OUT) != 0)

Definition at line 283 of file predicate.c.

◆ SxactIsCommitted

#define SxactIsCommitted (   sxact)    (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)

Definition at line 277 of file predicate.c.

◆ SxactIsDeferrableWaiting

#define SxactIsDeferrableWaiting (   sxact)    (((sxact)->flags & SXACT_FLAG_DEFERRABLE_WAITING) != 0)

Definition at line 290 of file predicate.c.

◆ SxactIsDoomed

#define SxactIsDoomed (   sxact)    (((sxact)->flags & SXACT_FLAG_DOOMED) != 0)

Definition at line 280 of file predicate.c.

◆ SxactIsOnFinishedList

#define SxactIsOnFinishedList (   sxact)    (!dlist_node_is_detached(&(sxact)->finishedLink))

Definition at line 267 of file predicate.c.

◆ SxactIsPartiallyReleased

#define SxactIsPartiallyReleased (   sxact)    (((sxact)->flags & SXACT_FLAG_PARTIALLY_RELEASED) != 0)

Definition at line 293 of file predicate.c.

◆ SxactIsPrepared

#define SxactIsPrepared (   sxact)    (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)

Definition at line 278 of file predicate.c.

◆ SxactIsReadOnly

#define SxactIsReadOnly (   sxact)    (((sxact)->flags & SXACT_FLAG_READ_ONLY) != 0)

Definition at line 281 of file predicate.c.

◆ SxactIsRolledBack

#define SxactIsRolledBack (   sxact)    (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0)

Definition at line 279 of file predicate.c.

◆ SxactIsROSafe

#define SxactIsROSafe (   sxact)    (((sxact)->flags & SXACT_FLAG_RO_SAFE) != 0)

Definition at line 291 of file predicate.c.

◆ SxactIsROUnsafe

#define SxactIsROUnsafe (   sxact)    (((sxact)->flags & SXACT_FLAG_RO_UNSAFE) != 0)

Definition at line 292 of file predicate.c.

◆ TargetTagIsCoveredBy

#define TargetTagIsCoveredBy (   covered_target,
  covering_target 
)
Value:
((GET_PREDICATELOCKTARGETTAG_RELATION(covered_target) == /* (2) */ \
GET_PREDICATELOCKTARGETTAG_RELATION(covering_target)) \
&& (GET_PREDICATELOCKTARGETTAG_OFFSET(covering_target) == \
InvalidOffsetNumber) /* (3) */ \
&& (((GET_PREDICATELOCKTARGETTAG_OFFSET(covered_target) != \
InvalidOffsetNumber) /* (4a) */ \
&& (GET_PREDICATELOCKTARGETTAG_PAGE(covering_target) == \
GET_PREDICATELOCKTARGETTAG_PAGE(covered_target))) \
|| ((GET_PREDICATELOCKTARGETTAG_PAGE(covering_target) == \
InvalidBlockNumber) /* (4b) */ \
&& (GET_PREDICATELOCKTARGETTAG_PAGE(covered_target) \
&& (GET_PREDICATELOCKTARGETTAG_DB(covered_target) == /* (1) */ \
GET_PREDICATELOCKTARGETTAG_DB(covering_target)))
#define InvalidBlockNumber
Definition: block.h:33
#define InvalidOffsetNumber
Definition: off.h:26
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
#define GET_PREDICATELOCKTARGETTAG_PAGE(locktag)
#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag)

Definition at line 233 of file predicate.c.

Typedef Documentation

◆ SerialControl

Definition at line 352 of file predicate.c.

◆ SerialControlData

Function Documentation

◆ AtPrepare_PredicateLocks()

void AtPrepare_PredicateLocks ( void  )

Definition at line 4788 of file predicate.c.

4789{
4790 SERIALIZABLEXACT *sxact;
4792 TwoPhasePredicateXactRecord *xactRecord;
4793 TwoPhasePredicateLockRecord *lockRecord;
4794 dlist_iter iter;
4795
4796 sxact = MySerializableXact;
4797 xactRecord = &(record.data.xactRecord);
4798 lockRecord = &(record.data.lockRecord);
4799
4801 return;
4802
4803 /* Generate an xact record for our SERIALIZABLEXACT */
4805 xactRecord->xmin = MySerializableXact->xmin;
4806 xactRecord->flags = MySerializableXact->flags;
4807
4808 /*
4809 * Note that we don't include the list of conflicts in our out in the
4810 * statefile, because new conflicts can be added even after the
4811 * transaction prepares. We'll just make a conservative assumption during
4812 * recovery instead.
4813 */
4814
4816 &record, sizeof(record));
4817
4818 /*
4819 * Generate a lock record for each lock.
4820 *
4821 * To do this, we need to walk the predicate lock list in our sxact rather
4822 * than using the local predicate lock table because the latter is not
4823 * guaranteed to be accurate.
4824 */
4825 LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4826
4827 /*
4828 * No need to take sxact->perXactPredicateListLock in parallel mode
4829 * because there cannot be any parallel workers running while we are
4830 * preparing a transaction.
4831 */
4833
4834 dlist_foreach(iter, &sxact->predicateLocks)
4835 {
4836 PREDICATELOCK *predlock =
4837 dlist_container(PREDICATELOCK, xactLink, iter.cur);
4838
4840 lockRecord->target = predlock->tag.myTarget->tag;
4841
4843 &record, sizeof(record));
4844 }
4845
4846 LWLockRelease(SerializablePredicateListLock);
4847}
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:1174
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894
@ LW_SHARED
Definition: lwlock.h:113
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:421
@ TWOPHASEPREDICATERECORD_XACT
@ TWOPHASEPREDICATERECORD_LOCK
#define InvalidSerializableXact
PREDICATELOCKTARGET * myTarget
PREDICATELOCKTARGETTAG tag
PREDICATELOCKTAG tag
PREDICATELOCKTARGETTAG target
TwoPhasePredicateRecordType type
union TwoPhasePredicateRecord::@129 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:1271
#define TWOPHASE_RM_PREDICATELOCK_ID
Definition: twophase_rmgr.h:30

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

5055{
5056
5058
5062}
static void CreateLocalPredicateLockHash(void)
Definition: predicate.c:1938

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

Referenced by ParallelWorkerMain().

◆ check_serial_buffers()

bool check_serial_buffers ( int *  newval,
void **  extra,
GucSource  source 
)

Definition at line 847 of file predicate.c.

848{
849 return check_slru_buffers("serializable_buffers", newval);
850}
#define newval
bool check_slru_buffers(const char *name, int *newval)
Definition: slru.c:355

References check_slru_buffers(), and newval.

◆ CheckAndPromotePredicateLockRequest()

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2324 of file predicate.c.

2325{
2326 PREDICATELOCKTARGETTAG targettag,
2327 nexttag,
2328 promotiontag;
2329 LOCALPREDICATELOCK *parentlock;
2330 bool found,
2331 promote;
2332
2333 promote = false;
2334
2335 targettag = *reqtag;
2336
2337 /* check parents iteratively */
2338 while (GetParentPredicateLockTag(&targettag, &nexttag))
2339 {
2340 targettag = nexttag;
2342 &targettag,
2343 HASH_ENTER,
2344 &found);
2345 if (!found)
2346 {
2347 parentlock->held = false;
2348 parentlock->childLocks = 1;
2349 }
2350 else
2351 parentlock->childLocks++;
2352
2353 if (parentlock->childLocks >
2354 MaxPredicateChildLocks(&targettag))
2355 {
2356 /*
2357 * We should promote to this parent lock. Continue to check its
2358 * ancestors, however, both to get their child counts right and to
2359 * check whether we should just go ahead and promote to one of
2360 * them.
2361 */
2362 promotiontag = targettag;
2363 promote = true;
2364 }
2365 }
2366
2367 if (promote)
2368 {
2369 /* acquire coarsest ancestor eligible for promotion */
2370 PredicateLockAcquire(&promotiontag);
2371 return true;
2372 }
2373 else
2374 return false;
2375}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:952
@ HASH_ENTER
Definition: hsearch.h:114
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2515
static HTAB * LocalPredicateLockHash
Definition: predicate.c:414
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:2070
static int MaxPredicateChildLocks(const PREDICATELOCKTARGETTAG *tag)
Definition: predicate.c:2287

References LOCALPREDICATELOCK::childLocks, GetParentPredicateLockTag(), HASH_ENTER, hash_search(), LOCALPREDICATELOCK::held, LocalPredicateLockHash, MaxPredicateChildLocks(), and PredicateLockAcquire().

Referenced by PredicateLockAcquire().

◆ CheckForSerializableConflictIn()

void CheckForSerializableConflictIn ( Relation  relation,
const ItemPointerData tid,
BlockNumber  blkno 
)

Definition at line 4334 of file predicate.c.

4335{
4336 PREDICATELOCKTARGETTAG targettag;
4337
4338 if (!SerializationNeededForWrite(relation))
4339 return;
4340
4341 /* Check if someone else has already decided that we need to die */
4343 ereport(ERROR,
4345 errmsg("could not serialize access due to read/write dependencies among transactions"),
4346 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4347 errhint("The transaction might succeed if retried.")));
4348
4349 /*
4350 * We're doing a write which might cause rw-conflicts now or later.
4351 * Memorize that fact.
4352 */
4353 MyXactDidWrite = true;
4354
4355 /*
4356 * It is important that we check for locks from the finest granularity to
4357 * the coarsest granularity, so that granularity promotion doesn't cause
4358 * us to miss a lock. The new (coarser) lock will be acquired before the
4359 * old (finer) locks are released.
4360 *
4361 * It is not possible to take and hold a lock across the checks for all
4362 * granularities because each target could be in a separate partition.
4363 */
4364 if (tid != NULL)
4365 {
4367 relation->rd_locator.dbOid,
4368 relation->rd_id,
4371 CheckTargetForConflictsIn(&targettag);
4372 }
4373
4374 if (blkno != InvalidBlockNumber)
4375 {
4377 relation->rd_locator.dbOid,
4378 relation->rd_id,
4379 blkno);
4380 CheckTargetForConflictsIn(&targettag);
4381 }
4382
4384 relation->rd_locator.dbOid,
4385 relation->rd_id);
4386 CheckTargetForConflictsIn(&targettag);
4387}
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1243
int errhint(const char *fmt,...)
Definition: elog.c:1330
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
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:4164
#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 4021 of file predicate.c.

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

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

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

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:549
#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
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1347
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition: slru.c:1433
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 4417 of file predicate.c.

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

◆ CheckTargetForConflictsIn()

static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag)
static

Definition at line 4164 of file predicate.c.

4165{
4166 uint32 targettaghash;
4167 LWLock *partitionLock;
4168 PREDICATELOCKTARGET *target;
4169 PREDICATELOCK *mypredlock = NULL;
4170 PREDICATELOCKTAG mypredlocktag;
4171 dlist_mutable_iter iter;
4172
4174
4175 /*
4176 * The same hash and LW lock apply to the lock target and the lock itself.
4177 */
4178 targettaghash = PredicateLockTargetTagHashCode(targettag);
4179 partitionLock = PredicateLockHashPartitionLock(targettaghash);
4180 LWLockAcquire(partitionLock, LW_SHARED);
4181 target = (PREDICATELOCKTARGET *)
4183 targettag, targettaghash,
4184 HASH_FIND, NULL);
4185 if (!target)
4186 {
4187 /* Nothing has this target locked; we're done here. */
4188 LWLockRelease(partitionLock);
4189 return;
4190 }
4191
4192 /*
4193 * Each lock for an overlapping transaction represents a conflict: a
4194 * rw-dependency in to this transaction.
4195 */
4196 LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4197
4198 dlist_foreach_modify(iter, &target->predicateLocks)
4199 {
4200 PREDICATELOCK *predlock =
4201 dlist_container(PREDICATELOCK, targetLink, iter.cur);
4202 SERIALIZABLEXACT *sxact = predlock->tag.myXact;
4203
4204 if (sxact == MySerializableXact)
4205 {
4206 /*
4207 * If we're getting a write lock on a tuple, we don't need a
4208 * predicate (SIREAD) lock on the same tuple. We can safely remove
4209 * our SIREAD lock, but we'll defer doing so until after the loop
4210 * because that requires upgrading to an exclusive partition lock.
4211 *
4212 * We can't use this optimization within a subtransaction because
4213 * the subtransaction could roll back, and we would be left
4214 * without any lock at the top level.
4215 */
4216 if (!IsSubTransaction()
4217 && GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
4218 {
4219 mypredlock = predlock;
4220 mypredlocktag = predlock->tag;
4221 }
4222 }
4223 else if (!SxactIsDoomed(sxact)
4224 && (!SxactIsCommitted(sxact)
4226 sxact->finishedBefore))
4228 {
4229 LWLockRelease(SerializableXactHashLock);
4230 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4231
4232 /*
4233 * Re-check after getting exclusive lock because the other
4234 * transaction may have flagged a conflict.
4235 */
4236 if (!SxactIsDoomed(sxact)
4237 && (!SxactIsCommitted(sxact)
4239 sxact->finishedBefore))
4241 {
4243 }
4244
4245 LWLockRelease(SerializableXactHashLock);
4246 LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4247 }
4248 }
4249 LWLockRelease(SerializableXactHashLock);
4250 LWLockRelease(partitionLock);
4251
4252 /*
4253 * If we found one of our own SIREAD locks to remove, remove it now.
4254 *
4255 * At this point our transaction already has a RowExclusiveLock on the
4256 * relation, so we are OK to drop the predicate lock on the tuple, if
4257 * found, without fearing that another write against the tuple will occur
4258 * before the MVCC information makes it to the buffer.
4259 */
4260 if (mypredlock != NULL)
4261 {
4262 uint32 predlockhashcode;
4263 PREDICATELOCK *rmpredlock;
4264
4265 LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
4266 if (IsInParallelMode())
4268 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4269 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4270
4271 /*
4272 * Remove the predicate lock from shared memory, if it wasn't removed
4273 * while the locks were released. One way that could happen is from
4274 * autovacuum cleaning up an index.
4275 */
4277 (&mypredlocktag, targettaghash);
4278 rmpredlock = (PREDICATELOCK *)
4280 &mypredlocktag,
4281 predlockhashcode,
4282 HASH_FIND, NULL);
4283 if (rmpredlock != NULL)
4284 {
4285 Assert(rmpredlock == mypredlock);
4286
4287 dlist_delete(&(mypredlock->targetLink));
4288 dlist_delete(&(mypredlock->xactLink));
4289
4290 rmpredlock = (PREDICATELOCK *)
4292 &mypredlocktag,
4293 predlockhashcode,
4294 HASH_REMOVE, NULL);
4295 Assert(rmpredlock == mypredlock);
4296
4297 RemoveTargetIfNoLongerUsed(target, targettaghash);
4298 }
4299
4300 LWLockRelease(SerializableXactHashLock);
4301 LWLockRelease(partitionLock);
4302 if (IsInParallelMode())
4304 LWLockRelease(SerializablePredicateListLock);
4305
4306 if (rmpredlock != NULL)
4307 {
4308 /*
4309 * Remove entry in local lock table if it exists. It's OK if it
4310 * doesn't exist; that means the lock was transferred to a new
4311 * target by a different backend.
4312 */
4314 targettag, targettaghash,
4315 HASH_REMOVE, NULL);
4316
4317 DecrementParentLocks(targettag);
4318 }
4319 }
4320}
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:965
@ HASH_REMOVE
Definition: hsearch.h:115
static void dlist_delete(dlist_node *node)
Definition: ilist.h:405
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2389
static HTAB * PredicateLockHash
Definition: predicate.c:398
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:303
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2181
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:316
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:258
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:272
Definition: lwlock.h:42
TransactionId finishedBefore
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.h:263
bool IsSubTransaction(void)
Definition: xact.c:5062
bool IsInParallelMode(void)
Definition: xact.c:1090

References Assert(), dlist_mutable_iter::cur, DecrementParentLocks(), dlist_container, dlist_delete(), dlist_foreach_modify, SERIALIZABLEXACT::finishedBefore, FlagRWConflict(), GET_PREDICATELOCKTARGETTAG_OFFSET, GetTransactionSnapshot(), HASH_FIND, HASH_REMOVE, hash_search_with_hash_value(), InvalidSerializableXact, IsInParallelMode(), IsSubTransaction(), LocalPredicateLockHash, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myXact, SERIALIZABLEXACT::perXactPredicateListLock, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredicateLockTargetTagHashCode, RemoveTargetIfNoLongerUsed(), RWConflictExists(), SxactIsCommitted, SxactIsDoomed, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdPrecedes(), and PREDICATELOCK::xactLink.

Referenced by CheckForSerializableConflictIn().

◆ ClearOldPredicateLocks()

static void ClearOldPredicateLocks ( void  )
static

Definition at line 3695 of file predicate.c.

3696{
3697 dlist_mutable_iter iter;
3698
3699 /*
3700 * Loop through finished transactions. They are in commit order, so we can
3701 * stop as soon as we find one that's still interesting.
3702 */
3703 LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3704 LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3706 {
3707 SERIALIZABLEXACT *finishedSxact =
3708 dlist_container(SERIALIZABLEXACT, finishedLink, iter.cur);
3709
3713 {
3714 /*
3715 * This transaction committed before any in-progress transaction
3716 * took its snapshot. It's no longer interesting.
3717 */
3718 LWLockRelease(SerializableXactHashLock);
3719 dlist_delete_thoroughly(&finishedSxact->finishedLink);
3720 ReleaseOneSerializableXact(finishedSxact, false, false);
3721 LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3722 }
3723 else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3724 && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3725 {
3726 /*
3727 * Any active transactions that took their snapshot before this
3728 * transaction committed are read-only, so we can clear part of
3729 * its state.
3730 */
3731 LWLockRelease(SerializableXactHashLock);
3732
3733 if (SxactIsReadOnly(finishedSxact))
3734 {
3735 /* A read-only transaction can be removed entirely */
3736 dlist_delete_thoroughly(&(finishedSxact->finishedLink));
3737 ReleaseOneSerializableXact(finishedSxact, false, false);
3738 }
3739 else
3740 {
3741 /*
3742 * A read-write transaction can only be partially cleared. We
3743 * need to keep the SERIALIZABLEXACT but can release the
3744 * SIREAD locks and conflicts in.
3745 */
3746 ReleaseOneSerializableXact(finishedSxact, true, false);
3747 }
3748
3750 LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3751 }
3752 else
3753 {
3754 /* Still interesting. */
3755 break;
3756 }
3757 }
3758 LWLockRelease(SerializableXactHashLock);
3759
3760 /*
3761 * Loop through predicate locks on dummy transaction for summarized data.
3762 */
3763 LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
3765 {
3766 PREDICATELOCK *predlock =
3767 dlist_container(PREDICATELOCK, xactLink, iter.cur);
3768 bool canDoPartialCleanup;
3769
3770 LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3771 Assert(predlock->commitSeqNo != 0);
3773 canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
3774 LWLockRelease(SerializableXactHashLock);
3775
3776 /*
3777 * If this lock originally belonged to an old enough transaction, we
3778 * can release it.
3779 */
3780 if (canDoPartialCleanup)
3781 {
3782 PREDICATELOCKTAG tag;
3783 PREDICATELOCKTARGET *target;
3784 PREDICATELOCKTARGETTAG targettag;
3785 uint32 targettaghash;
3786 LWLock *partitionLock;
3787
3788 tag = predlock->tag;
3789 target = tag.myTarget;
3790 targettag = target->tag;
3791 targettaghash = PredicateLockTargetTagHashCode(&targettag);
3792 partitionLock = PredicateLockHashPartitionLock(targettaghash);
3793
3794 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3795
3796 dlist_delete(&(predlock->targetLink));
3797 dlist_delete(&(predlock->xactLink));
3798
3801 targettaghash),
3802 HASH_REMOVE, NULL);
3803 RemoveTargetIfNoLongerUsed(target, targettaghash);
3804
3805 LWLockRelease(partitionLock);
3806 }
3807 }
3808
3809 LWLockRelease(SerializablePredicateListLock);
3810 LWLockRelease(SerializableFinishedListLock);
3811}
static void dlist_delete_thoroughly(dlist_node *node)
Definition: ilist.h:416
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:362
static dlist_head * FinishedSerializableTransactions
Definition: predicate.c:399
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize)
Definition: predicate.c:3833
SerCommitSeqNo commitSeqNo
SerCommitSeqNo CanPartialClearThrough
SerCommitSeqNo HavePartialClearedThrough
SerCommitSeqNo commitSeqNo
static bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.h:282

References Assert(), PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, PREDICATELOCK::commitSeqNo, dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_delete_thoroughly(), dlist_foreach_modify, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, HASH_REMOVE, hash_search_with_hash_value(), PredXactListData::HavePartialClearedThrough, InvalidSerCommitSeqNo, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, OldCommittedSxact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, PredXact, ReleaseOneSerializableXact(), RemoveTargetIfNoLongerUsed(), PredXactListData::SxactGlobalXmin, SxactIsReadOnly, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdIsValid, TransactionIdPrecedesOrEquals(), and PREDICATELOCK::xactLink.

Referenced by ReleasePredicateLocks().

◆ CoarserLockCovers()

static bool CoarserLockCovers ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2109 of file predicate.c.

2110{
2111 PREDICATELOCKTARGETTAG targettag,
2112 parenttag;
2113
2114 targettag = *newtargettag;
2115
2116 /* check parents iteratively until no more */
2117 while (GetParentPredicateLockTag(&targettag, &parenttag))
2118 {
2119 targettag = parenttag;
2120 if (PredicateLockExists(&targettag))
2121 return true;
2122 }
2123
2124 /* no more parents to check; lock is not covered */
2125 return false;
2126}
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2043

References GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

◆ CreateLocalPredicateLockHash()

static void CreateLocalPredicateLockHash ( void  )
static

Definition at line 1938 of file predicate.c.

1939{
1940 HASHCTL hash_ctl;
1941
1942 /* Initialize the backend-local hash table of parent locks */
1944 hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1945 hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1946 LocalPredicateLockHash = hash_create("Local predicate lock",
1948 &hash_ctl,
1950}
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:358
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
int max_predicate_locks_per_xact
Definition: predicate.c:371
struct LOCALPREDICATELOCK LOCALPREDICATELOCK
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76

References Assert(), HASHCTL::entrysize, HASH_BLOBS, hash_create(), HASH_ELEM, HASHCTL::keysize, LocalPredicateLockHash, and max_predicate_locks_per_xact.

Referenced by AttachSerializableXact(), and GetSerializableTransactionSnapshotInt().

◆ CreatePredicateLock()

static void CreatePredicateLock ( const PREDICATELOCKTARGETTAG targettag,
uint32  targettaghash,
SERIALIZABLEXACT sxact 
)
static

Definition at line 2451 of file predicate.c.

2454{
2455 PREDICATELOCKTARGET *target;
2456 PREDICATELOCKTAG locktag;
2457 PREDICATELOCK *lock;
2458 LWLock *partitionLock;
2459 bool found;
2460
2461 partitionLock = PredicateLockHashPartitionLock(targettaghash);
2462
2463 LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2464 if (IsInParallelMode())
2466 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2467
2468 /* Make sure that the target is represented. */
2469 target = (PREDICATELOCKTARGET *)
2471 targettag, targettaghash,
2472 HASH_ENTER_NULL, &found);
2473 if (!target)
2474 ereport(ERROR,
2475 (errcode(ERRCODE_OUT_OF_MEMORY),
2476 errmsg("out of shared memory"),
2477 errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
2478 if (!found)
2479 dlist_init(&target->predicateLocks);
2480
2481 /* We've got the sxact and target, make sure they're joined. */
2482 locktag.myTarget = target;
2483 locktag.myXact = sxact;
2484 lock = (PREDICATELOCK *)
2486 PredicateLockHashCodeFromTargetHashCode(&locktag, targettaghash),
2487 HASH_ENTER_NULL, &found);
2488 if (!lock)
2489 ereport(ERROR,
2490 (errcode(ERRCODE_OUT_OF_MEMORY),
2491 errmsg("out of shared memory"),
2492 errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
2493
2494 if (!found)
2495 {
2496 dlist_push_tail(&target->predicateLocks, &lock->targetLink);
2497 dlist_push_tail(&sxact->predicateLocks, &lock->xactLink);
2499 }
2500
2501 LWLockRelease(partitionLock);
2502 if (IsInParallelMode())
2504 LWLockRelease(SerializablePredicateListLock);
2505}
@ HASH_ENTER_NULL
Definition: hsearch.h:116
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

References PREDICATELOCK::commitSeqNo, dlist_init(), dlist_push_tail(), ereport, errcode(), errhint(), errmsg(), ERROR, HASH_ENTER_NULL, hash_search_with_hash_value(), InvalidSerCommitSeqNo, IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, SERIALIZABLEXACT::perXactPredicateListLock, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by predicatelock_twophase_recover(), and PredicateLockAcquire().

◆ CreatePredXact()

static SERIALIZABLEXACT * CreatePredXact ( void  )
static

◆ DecrementParentLocks()

static void DecrementParentLocks ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2389 of file predicate.c.

2390{
2391 PREDICATELOCKTARGETTAG parenttag,
2392 nexttag;
2393
2394 parenttag = *targettag;
2395
2396 while (GetParentPredicateLockTag(&parenttag, &nexttag))
2397 {
2398 uint32 targettaghash;
2399 LOCALPREDICATELOCK *parentlock,
2401
2402 parenttag = nexttag;
2403 targettaghash = PredicateLockTargetTagHashCode(&parenttag);
2404 parentlock = (LOCALPREDICATELOCK *)
2406 &parenttag, targettaghash,
2407 HASH_FIND, NULL);
2408
2409 /*
2410 * There's a small chance the parent lock doesn't exist in the lock
2411 * table. This can happen if we prematurely removed it because an
2412 * index split caused the child refcount to be off.
2413 */
2414 if (parentlock == NULL)
2415 continue;
2416
2417 parentlock->childLocks--;
2418
2419 /*
2420 * Under similar circumstances the parent lock's refcount might be
2421 * zero. This only happens if we're holding that lock (otherwise we
2422 * would have removed the entry).
2423 */
2424 if (parentlock->childLocks < 0)
2425 {
2426 Assert(parentlock->held);
2427 parentlock->childLocks = 0;
2428 }
2429
2430 if ((parentlock->childLocks == 0) && (!parentlock->held))
2431 {
2432 rmlock = (LOCALPREDICATELOCK *)
2434 &parenttag, targettaghash,
2435 HASH_REMOVE, NULL);
2436 Assert(rmlock == parentlock);
2437 }
2438 }
2439}
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:229

References Assert(), LOCALPREDICATELOCK::childLocks, GetParentPredicateLockTag(), HASH_FIND, HASH_REMOVE, hash_search_with_hash_value(), LOCALPREDICATELOCK::held, LocalPredicateLockHash, PG_USED_FOR_ASSERTS_ONLY, and PredicateLockTargetTagHashCode.

Referenced by CheckTargetForConflictsIn(), and DeleteChildTargetLocks().

◆ DeleteChildTargetLocks()

static void DeleteChildTargetLocks ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2212 of file predicate.c.

2213{
2214 SERIALIZABLEXACT *sxact;
2215 PREDICATELOCK *predlock;
2216 dlist_mutable_iter iter;
2217
2218 LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2219 sxact = MySerializableXact;
2220 if (IsInParallelMode())
2222
2224 {
2225 PREDICATELOCKTAG oldlocktag;
2226 PREDICATELOCKTARGET *oldtarget;
2227 PREDICATELOCKTARGETTAG oldtargettag;
2228
2229 predlock = dlist_container(PREDICATELOCK, xactLink, iter.cur);
2230
2231 oldlocktag = predlock->tag;
2232 Assert(oldlocktag.myXact == sxact);
2233 oldtarget = oldlocktag.myTarget;
2234 oldtargettag = oldtarget->tag;
2235
2236 if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
2237 {
2238 uint32 oldtargettaghash;
2239 LWLock *partitionLock;
2241
2242 oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2243 partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2244
2245 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2246
2247 dlist_delete(&predlock->xactLink);
2248 dlist_delete(&predlock->targetLink);
2249 rmpredlock = hash_search_with_hash_value
2251 &oldlocktag,
2253 oldtargettaghash),
2254 HASH_REMOVE, NULL);
2255 Assert(rmpredlock == predlock);
2256
2257 RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2258
2259 LWLockRelease(partitionLock);
2260
2261 DecrementParentLocks(&oldtargettag);
2262 }
2263 }
2264 if (IsInParallelMode())
2266 LWLockRelease(SerializablePredicateListLock);
2267}
#define TargetTagIsCoveredBy(covered_target, covering_target)
Definition: predicate.c:233

References Assert(), dlist_mutable_iter::cur, DecrementParentLocks(), dlist_container, dlist_delete(), dlist_foreach_modify, HASH_REMOVE, hash_search_with_hash_value(), IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, SERIALIZABLEXACT::perXactPredicateListLock, PG_USED_FOR_ASSERTS_ONLY, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, RemoveTargetIfNoLongerUsed(), PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TargetTagIsCoveredBy, and PREDICATELOCK::xactLink.

Referenced by PredicateLockAcquire().

◆ DeleteLockTarget()

static void DeleteLockTarget ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

Definition at line 2667 of file predicate.c.

2668{
2669 dlist_mutable_iter iter;
2670
2671 Assert(LWLockHeldByMeInMode(SerializablePredicateListLock,
2672 LW_EXCLUSIVE));
2674
2675 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2676
2677 dlist_foreach_modify(iter, &target->predicateLocks)
2678 {
2679 PREDICATELOCK *predlock =
2680 dlist_container(PREDICATELOCK, targetLink, iter.cur);
2681 bool found;
2682
2683 dlist_delete(&(predlock->xactLink));
2684 dlist_delete(&(predlock->targetLink));
2685
2688 &predlock->tag,
2690 targettaghash),
2691 HASH_REMOVE, &found);
2692 Assert(found);
2693 }
2694 LWLockRelease(SerializableXactHashLock);
2695
2696 /* Remove the target itself, if possible. */
2697 RemoveTargetIfNoLongerUsed(target, targettaghash);
2698}
bool LWLockHeldByMe(LWLock *lock)
Definition: lwlock.c:1977
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:2021

References Assert(), dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_foreach_modify, HASH_REMOVE, hash_search_with_hash_value(), LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMe(), LWLockHeldByMeInMode(), LWLockRelease(), PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PREDICATELOCKTARGET::predicateLocks, RemoveTargetIfNoLongerUsed(), PREDICATELOCK::tag, PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by TransferPredicateLocksToNewTarget().

◆ DropAllPredicateLocksFromTable()

static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
)
static

Definition at line 2935 of file predicate.c.

2936{
2937 HASH_SEQ_STATUS seqstat;
2938 PREDICATELOCKTARGET *oldtarget;
2939 PREDICATELOCKTARGET *heaptarget;
2940 Oid dbId;
2941 Oid relId;
2942 Oid heapId;
2943 int i;
2944 bool isIndex;
2945 bool found;
2946 uint32 heaptargettaghash;
2947
2948 /*
2949 * Bail out quickly if there are no serializable transactions running.
2950 * It's safe to check this without taking locks because the caller is
2951 * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
2952 * would matter here can be acquired while that is held.
2953 */
2955 return;
2956
2957 if (!PredicateLockingNeededForRelation(relation))
2958 return;
2959
2960 dbId = relation->rd_locator.dbOid;
2961 relId = relation->rd_id;
2962 if (relation->rd_index == NULL)
2963 {
2964 isIndex = false;
2965 heapId = relId;
2966 }
2967 else
2968 {
2969 isIndex = true;
2970 heapId = relation->rd_index->indrelid;
2971 }
2972 Assert(heapId != InvalidOid);
2973 Assert(transfer || !isIndex); /* index OID only makes sense with
2974 * transfer */
2975
2976 /* Retrieve first time needed, then keep. */
2977 heaptargettaghash = 0;
2978 heaptarget = NULL;
2979
2980 /* Acquire locks on all lock partitions */
2981 LWLockAcquire(SerializablePredicateListLock, LW_EXCLUSIVE);
2982 for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
2984 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2985
2986 /*
2987 * Remove the dummy entry to give us scratch space, so we know we'll be
2988 * able to create the new lock target.
2989 */
2990 if (transfer)
2991 RemoveScratchTarget(true);
2992
2993 /* Scan through target map */
2995
2996 while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
2997 {
2998 dlist_mutable_iter iter;
2999
3000 /*
3001 * Check whether this is a target which needs attention.
3002 */
3003 if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) != relId)
3004 continue; /* wrong relation id */
3005 if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
3006 continue; /* wrong database id */
3007 if (transfer && !isIndex
3009 continue; /* already the right lock */
3010
3011 /*
3012 * If we made it here, we have work to do. We make sure the heap
3013 * relation lock exists, then we walk the list of predicate locks for
3014 * the old target we found, moving all locks to the heap relation lock
3015 * -- unless they already hold that.
3016 */
3017
3018 /*
3019 * First make sure we have the heap relation target. We only need to
3020 * do this once.
3021 */
3022 if (transfer && heaptarget == NULL)
3023 {
3024 PREDICATELOCKTARGETTAG heaptargettag;
3025
3026 SET_PREDICATELOCKTARGETTAG_RELATION(heaptargettag, dbId, heapId);
3027 heaptargettaghash = PredicateLockTargetTagHashCode(&heaptargettag);
3029 &heaptargettag,
3030 heaptargettaghash,
3031 HASH_ENTER, &found);
3032 if (!found)
3033 dlist_init(&heaptarget->predicateLocks);
3034 }
3035
3036 /*
3037 * Loop through all the locks on the old target, replacing them with
3038 * locks on the new target.
3039 */
3040 dlist_foreach_modify(iter, &oldtarget->predicateLocks)
3041 {
3042 PREDICATELOCK *oldpredlock =
3043 dlist_container(PREDICATELOCK, targetLink, iter.cur);
3044 PREDICATELOCK *newpredlock;
3045 SerCommitSeqNo oldCommitSeqNo;
3046 SERIALIZABLEXACT *oldXact;
3047
3048 /*
3049 * Remove the old lock first. This avoids the chance of running
3050 * out of lock structure entries for the hash table.
3051 */
3052 oldCommitSeqNo = oldpredlock->commitSeqNo;
3053 oldXact = oldpredlock->tag.myXact;
3054
3055 dlist_delete(&(oldpredlock->xactLink));
3056
3057 /*
3058 * No need for retail delete from oldtarget list, we're removing
3059 * the whole target anyway.
3060 */
3062 &oldpredlock->tag,
3063 HASH_REMOVE, &found);
3064 Assert(found);
3065
3066 if (transfer)
3067 {
3068 PREDICATELOCKTAG newpredlocktag;
3069
3070 newpredlocktag.myTarget = heaptarget;
3071 newpredlocktag.myXact = oldXact;
3072 newpredlock = (PREDICATELOCK *)
3074 &newpredlocktag,
3076 heaptargettaghash),
3077 HASH_ENTER,
3078 &found);
3079 if (!found)
3080 {
3081 dlist_push_tail(&(heaptarget->predicateLocks),
3082 &(newpredlock->targetLink));
3083 dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
3084 &(newpredlock->xactLink));
3085 newpredlock->commitSeqNo = oldCommitSeqNo;
3086 }
3087 else
3088 {
3089 if (newpredlock->commitSeqNo < oldCommitSeqNo)
3090 newpredlock->commitSeqNo = oldCommitSeqNo;
3091 }
3092
3093 Assert(newpredlock->commitSeqNo != 0);
3094 Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
3095 || (newpredlock->tag.myXact == OldCommittedSxact));
3096 }
3097 }
3098
3100 &found);
3101 Assert(found);
3102 }
3103
3104 /* Put the scratch entry back */
3105 if (transfer)
3107
3108 /* Release locks in reverse order */
3109 LWLockRelease(SerializableXactHashLock);
3110 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
3112 LWLockRelease(SerializablePredicateListLock);
3113}
#define InvalidOid
Definition: postgres_ext.h:37
static bool PredicateLockingNeededForRelation(Relation relation)
Definition: predicate.c:498
static void RestoreScratchTarget(bool lockheld)
Definition: predicate.c:2159
static void RemoveScratchTarget(bool lockheld)
Definition: predicate.c:2138
@ PREDLOCKTAG_RELATION
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)

References Assert(), PREDICATELOCK::commitSeqNo, dlist_mutable_iter::cur, RelFileLocator::dbOid, dlist_container, dlist_delete(), dlist_foreach_modify, dlist_init(), dlist_push_tail(), GET_PREDICATELOCKTARGETTAG_DB, GET_PREDICATELOCKTARGETTAG_RELATION, GET_PREDICATELOCKTARGETTAG_TYPE, HASH_ENTER, HASH_REMOVE, hash_search(), hash_search_with_hash_value(), hash_seq_init(), hash_seq_search(), i, InvalidOid, InvalidSerCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, NUM_PREDICATELOCK_PARTITIONS, OldCommittedSxact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLockByIndex, PredicateLockingNeededForRelation(), SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredicateLockTargetTagHashCode, PREDLOCKTAG_RELATION, PredXact, RelationData::rd_id, RelationData::rd_index, RelationData::rd_locator, RemoveScratchTarget(), RestoreScratchTarget(), SET_PREDICATELOCKTARGETTAG_RELATION, PredXactListData::SxactGlobalXmin, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdIsValid, and PREDICATELOCK::xactLink.

Referenced by TransferPredicateLocksToHeapRelation().

◆ FlagRWConflict()

static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4499 of file predicate.c.

4500{
4501 Assert(reader != writer);
4502
4503 /* First, see if this conflict causes failure. */
4505
4506 /* Actually do the conflict flagging. */
4507 if (reader == OldCommittedSxact)
4509 else if (writer == OldCommittedSxact)
4511 else
4512 SetRWConflict(reader, writer);
4513}
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:643
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4534
#define SXACT_FLAG_SUMMARY_CONFLICT_IN

References Assert(), SERIALIZABLEXACT::flags, OldCommittedSxact, OnConflict_CheckForSerializationFailure(), SetRWConflict(), SXACT_FLAG_SUMMARY_CONFLICT_IN, and SXACT_FLAG_SUMMARY_CONFLICT_OUT.

Referenced by CheckForSerializableConflictOut(), CheckTableForSerializableConflictIn(), and CheckTargetForConflictsIn().

◆ FlagSxactUnsafe()

static void FlagSxactUnsafe ( SERIALIZABLEXACT sxact)
static

Definition at line 699 of file predicate.c.

700{
702
703 Assert(SxactIsReadOnly(sxact));
704 Assert(!SxactIsROSafe(sxact));
705
706 sxact->flags |= SXACT_FLAG_RO_UNSAFE;
707
708 /*
709 * We know this isn't a safe snapshot, so we can stop looking for other
710 * potential conflicts.
711 */
713 {
714 RWConflict conflict =
715 dlist_container(RWConflictData, inLink, iter.cur);
716
717 Assert(!SxactIsReadOnly(conflict->sxactOut));
718 Assert(sxact == conflict->sxactIn);
719
720 ReleaseRWConflict(conflict);
721 }
722}
#define SxactIsROSafe(sxact)
Definition: predicate.c:291
static void ReleaseRWConflict(RWConflict conflict)
Definition: predicate.c:691
#define SXACT_FLAG_RO_UNSAFE
SERIALIZABLEXACT * sxactIn
SERIALIZABLEXACT * sxactOut
dlist_head possibleUnsafeConflicts

References Assert(), dlist_mutable_iter::cur, dlist_container, dlist_foreach_modify, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::possibleUnsafeConflicts, ReleaseRWConflict(), SXACT_FLAG_RO_UNSAFE, RWConflictData::sxactIn, SxactIsReadOnly, SxactIsROSafe, and RWConflictData::sxactOut.

Referenced by ReleasePredicateLocks().

◆ GetParentPredicateLockTag()

static bool GetParentPredicateLockTag ( const PREDICATELOCKTARGETTAG tag,
PREDICATELOCKTARGETTAG parent 
)
static

Definition at line 2070 of file predicate.c.

2072{
2073 switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2074 {
2076 /* relation locks have no parent lock */
2077 return false;
2078
2079 case PREDLOCKTAG_PAGE:
2080 /* parent lock is relation lock */
2084
2085 return true;
2086
2087 case PREDLOCKTAG_TUPLE:
2088 /* parent lock is page lock */
2093 return true;
2094 }
2095
2096 /* not reachable */
2097 Assert(false);
2098 return false;
2099}
@ PREDLOCKTAG_PAGE
@ PREDLOCKTAG_TUPLE

References Assert(), GET_PREDICATELOCKTARGETTAG_DB, GET_PREDICATELOCKTARGETTAG_PAGE, GET_PREDICATELOCKTARGETTAG_RELATION, GET_PREDICATELOCKTARGETTAG_TYPE, PREDLOCKTAG_PAGE, PREDLOCKTAG_RELATION, PREDLOCKTAG_TUPLE, SET_PREDICATELOCKTARGETTAG_PAGE, and SET_PREDICATELOCKTARGETTAG_RELATION.

Referenced by CheckAndPromotePredicateLockRequest(), CoarserLockCovers(), DecrementParentLocks(), and PredicateLockPageSplit().

◆ GetPredicateLockStatusData()

PredicateLockData * GetPredicateLockStatusData ( void  )

Definition at line 1445 of file predicate.c.

1446{
1448 int i;
1449 int els,
1450 el;
1451 HASH_SEQ_STATUS seqstat;
1452 PREDICATELOCK *predlock;
1453
1455
1456 /*
1457 * To ensure consistency, take simultaneous locks on all partition locks
1458 * in ascending order, then SerializableXactHashLock.
1459 */
1460 for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
1462 LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1463
1464 /* Get number of locks and allocate appropriately-sized arrays. */
1466 data->nelements = els;
1467 data->locktags = palloc_array(PREDICATELOCKTARGETTAG, els);
1468 data->xacts = palloc_array(SERIALIZABLEXACT, els);
1469
1470
1471 /* Scan through PredicateLockHash and copy contents */
1473
1474 el = 0;
1475
1476 while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
1477 {
1478 data->locktags[el] = predlock->tag.myTarget->tag;
1479 data->xacts[el] = *predlock->tag.myXact;
1480 el++;
1481 }
1482
1483 Assert(el == els);
1484
1485 /* Release locks in reverse order */
1486 LWLockRelease(SerializableXactHashLock);
1487 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1489
1490 return data;
1491}
int64 hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1336
#define palloc_object(type)
Definition: fe_memutils.h:74
#define palloc_array(type, count)
Definition: fe_memutils.h:76
const void * data

References Assert(), data, hash_get_num_entries(), hash_seq_init(), hash_seq_search(), i, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, NUM_PREDICATELOCK_PARTITIONS, palloc_array, palloc_object, PredicateLockHash, PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::tag, and PREDICATELOCK::tag.

Referenced by pg_lock_status().

◆ GetSafeSnapshot()

static Snapshot GetSafeSnapshot ( Snapshot  origSnapshot)
static

Definition at line 1556 of file predicate.c.

1557{
1558 Snapshot snapshot;
1559
1561
1562 while (true)
1563 {
1564 /*
1565 * GetSerializableTransactionSnapshotInt is going to call
1566 * GetSnapshotData, so we need to provide it the static snapshot area
1567 * our caller passed to us. The pointer returned is actually the same
1568 * one passed to it, but we avoid assuming that here.
1569 */
1570 snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
1571 NULL, InvalidPid);
1572
1574 return snapshot; /* no concurrent r/w xacts; it's safe */
1575
1576 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1577
1578 /*
1579 * Wait for concurrent transactions to finish. Stop early if one of
1580 * them marked us as conflicted.
1581 */
1585 {
1586 LWLockRelease(SerializableXactHashLock);
1587 ProcWaitForSignal(WAIT_EVENT_SAFE_SNAPSHOT);
1588 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1589 }
1590 MySerializableXact->flags &= ~SXACT_FLAG_DEFERRABLE_WAITING;
1591
1593 {
1594 LWLockRelease(SerializableXactHashLock);
1595 break; /* success */
1596 }
1597
1598 LWLockRelease(SerializableXactHashLock);
1599
1600 /* else, need to retry... */
1603 errmsg_internal("deferrable snapshot was unsafe; trying a new one")));
1604 ReleasePredicateLocks(false, false);
1605 }
1606
1607 /*
1608 * Now we have a safe snapshot, so we don't need to do any further checks.
1609 */
1611 ReleasePredicateLocks(false, true);
1612
1613 return snapshot;
1614}
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1170
#define DEBUG2
Definition: elog.h:29
#define InvalidPid
Definition: miscadmin.h:32
#define SxactIsROUnsafe(sxact)
Definition: predicate.c:292
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, VirtualTransactionId *sourcevxid, int sourcepid)
Definition: predicate.c:1762
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3310
#define SXACT_FLAG_DEFERRABLE_WAITING
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1984
bool XactDeferrable
Definition: xact.c:86
bool XactReadOnly
Definition: xact.c:83

References Assert(), DEBUG2, dlist_is_empty(), ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errmsg_internal(), SERIALIZABLEXACT::flags, GetSerializableTransactionSnapshotInt(), InvalidPid, InvalidSerializableXact, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXACT::possibleUnsafeConflicts, ProcWaitForSignal(), ReleasePredicateLocks(), SXACT_FLAG_DEFERRABLE_WAITING, SxactIsROSafe, SxactIsROUnsafe, XactDeferrable, and XactReadOnly.

Referenced by GetSerializableTransactionSnapshot().

◆ GetSafeSnapshotBlockingPids()

int GetSafeSnapshotBlockingPids ( int  blocked_pid,
int *  output,
int  output_size 
)

Definition at line 1626 of file predicate.c.

1627{
1628 int num_written = 0;
1629 dlist_iter iter;
1630 SERIALIZABLEXACT *blocking_sxact = NULL;
1631
1632 LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1633
1634 /* Find blocked_pid's SERIALIZABLEXACT by linear search. */
1636 {
1637 SERIALIZABLEXACT *sxact =
1638 dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
1639
1640 if (sxact->pid == blocked_pid)
1641 {
1642 blocking_sxact = sxact;
1643 break;
1644 }
1645 }
1646
1647 /* Did we find it, and is it currently waiting in GetSafeSnapshot? */
1648 if (blocking_sxact != NULL && SxactIsDeferrableWaiting(blocking_sxact))
1649 {
1650 /* Traverse the list of possible unsafe conflicts collecting PIDs. */
1651 dlist_foreach(iter, &blocking_sxact->possibleUnsafeConflicts)
1652 {
1653 RWConflict possibleUnsafeConflict =
1654 dlist_container(RWConflictData, inLink, iter.cur);
1655
1656 output[num_written++] = possibleUnsafeConflict->sxactOut->pid;
1657
1658 if (num_written >= output_size)
1659 break;
1660 }
1661 }
1662
1663 LWLockRelease(SerializableXactHashLock);
1664
1665 return num_written;
1666}
FILE * output
#define SxactIsDeferrableWaiting(sxact)
Definition: predicate.c:290

References PredXactListData::activeList, dlist_iter::cur, dlist_container, dlist_foreach, LW_SHARED, LWLockAcquire(), LWLockRelease(), output, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, PredXact, SxactIsDeferrableWaiting, and RWConflictData::sxactOut.

Referenced by pg_isolation_test_session_is_blocked(), and pg_safe_snapshot_blocking_pids().

◆ GetSerializableTransactionSnapshot()

Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot)

Definition at line 1680 of file predicate.c.

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

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

Referenced by GetTransactionSnapshot().

◆ GetSerializableTransactionSnapshotInt()

static Snapshot GetSerializableTransactionSnapshotInt ( Snapshot  snapshot,
VirtualTransactionId sourcevxid,
int  sourcepid 
)
static

Definition at line 1762 of file predicate.c.

1765{
1766 PGPROC *proc;
1768 SERIALIZABLEXACT *sxact,
1769 *othersxact;
1770
1771 /* We only do this for serializable transactions. Once. */
1773
1775
1776 /*
1777 * Since all parts of a serializable transaction must use the same
1778 * snapshot, it is too late to establish one after a parallel operation
1779 * has begun.
1780 */
1781 if (IsInParallelMode())
1782 elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
1783
1784 proc = MyProc;
1785 Assert(proc != NULL);
1786 GET_VXID_FROM_PGPROC(vxid, *proc);
1787
1788 /*
1789 * First we get the sxact structure, which may involve looping and access
1790 * to the "finished" list to free a structure for use.
1791 *
1792 * We must hold SerializableXactHashLock when taking/checking the snapshot
1793 * to avoid race conditions, for much the same reasons that
1794 * GetSnapshotData takes the ProcArrayLock. Since we might have to
1795 * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
1796 * this means we have to create the sxact first, which is a bit annoying
1797 * (in particular, an elog(ERROR) in procarray.c would cause us to leak
1798 * the sxact). Consider refactoring to avoid this.
1799 */
1800#ifdef TEST_SUMMARIZE_SERIAL
1802#endif
1803 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1804 do
1805 {
1806 sxact = CreatePredXact();
1807 /* If null, push out committed sxact to SLRU summary & retry. */
1808 if (!sxact)
1809 {
1810 LWLockRelease(SerializableXactHashLock);
1812 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1813 }
1814 } while (!sxact);
1815
1816 /* Get the snapshot, or check that it's safe to use */
1817 if (!sourcevxid)
1818 snapshot = GetSnapshotData(snapshot);
1819 else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcevxid))
1820 {
1821 ReleasePredXact(sxact);
1822 LWLockRelease(SerializableXactHashLock);
1823 ereport(ERROR,
1824 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1825 errmsg("could not import the requested snapshot"),
1826 errdetail("The source process with PID %d is not running anymore.",
1827 sourcepid)));
1828 }
1829
1830 /*
1831 * If there are no serializable transactions which are not read-only, we
1832 * can "opt out" of predicate locking and conflict checking for a
1833 * read-only transaction.
1834 *
1835 * The reason this is safe is that a read-only transaction can only become
1836 * part of a dangerous structure if it overlaps a writable transaction
1837 * which in turn overlaps a writable transaction which committed before
1838 * the read-only transaction started. A new writable transaction can
1839 * overlap this one, but it can't meet the other condition of overlapping
1840 * a transaction which committed before this one started.
1841 */
1843 {
1844 ReleasePredXact(sxact);
1845 LWLockRelease(SerializableXactHashLock);
1846 return snapshot;
1847 }
1848
1849 /* Initialize the structure. */
1850 sxact->vxid = vxid;
1854 dlist_init(&(sxact->outConflicts));
1855 dlist_init(&(sxact->inConflicts));
1859 sxact->xmin = snapshot->xmin;
1860 sxact->pid = MyProcPid;
1861 sxact->pgprocno = MyProcNumber;
1862 dlist_init(&sxact->predicateLocks);
1864 sxact->flags = 0;
1865 if (XactReadOnly)
1866 {
1867 dlist_iter iter;
1868
1869 sxact->flags |= SXACT_FLAG_READ_ONLY;
1870
1871 /*
1872 * Register all concurrent r/w transactions as possible conflicts; if
1873 * all of them commit without any outgoing conflicts to earlier
1874 * transactions then this snapshot can be deemed safe (and we can run
1875 * without tracking predicate locks).
1876 */
1878 {
1879 othersxact = dlist_container(SERIALIZABLEXACT, xactLink, iter.cur);
1880
1881 if (!SxactIsCommitted(othersxact)
1882 && !SxactIsDoomed(othersxact)
1883 && !SxactIsReadOnly(othersxact))
1884 {
1885 SetPossibleUnsafeConflict(sxact, othersxact);
1886 }
1887 }
1888
1889 /*
1890 * If we didn't find any possibly unsafe conflicts because every
1891 * uncommitted writable transaction turned out to be doomed, then we
1892 * can "opt out" immediately. See comments above the earlier check
1893 * for PredXact->WritableSxactCount == 0.
1894 */
1896 {
1897 ReleasePredXact(sxact);
1898 LWLockRelease(SerializableXactHashLock);
1899 return snapshot;
1900 }
1901 }
1902 else
1903 {
1907 }
1908
1909 /* Maintain serializable global xmin info. */
1911 {
1913 PredXact->SxactGlobalXmin = snapshot->xmin;
1915 SerialSetActiveSerXmin(snapshot->xmin);
1916 }
1917 else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
1918 {
1921 }
1922 else
1923 {
1925 }
1926
1927 MySerializableXact = sxact;
1928 MyXactDidWrite = false; /* haven't written anything yet */
1929
1930 LWLockRelease(SerializableXactHashLock);
1931
1933
1934 return snapshot;
1935}
#define elog(elevel,...)
Definition: elog.h:226
int MyProcPid
Definition: globals.c:47
ProcNumber MyProcNumber
Definition: globals.c:90
int MaxBackends
Definition: globals.c:146
static void dlist_node_init(dlist_node *node)
Definition: ilist.h:325
#define GET_VXID_FROM_PGPROC(vxid_dst, proc)
Definition: lock.h:79
static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
Definition: predicate.c:666
static void ReleasePredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:596
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:582
static void SerialSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:990
static void SummarizeOldestCommittedSxact(void)
Definition: predicate.c:1501
#define SXACT_FLAG_READ_ONLY
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:2123
bool ProcArrayInstallImportedXmin(TransactionId xmin, VirtualTransactionId *sourcevxid)
Definition: procarray.c:2480
PGPROC * MyProc
Definition: proc.c:67
Definition: proc.h:179
SerCommitSeqNo LastSxactCommitSeqNo
VirtualTransactionId vxid
SerCommitSeqNo prepareSeqNo
TransactionId xmin
Definition: snapshot.h:153
static bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.h:297
#define InvalidTransactionId
Definition: transam.h:31
int max_prepared_xacts
Definition: twophase.c:116

References PredXactListData::activeList, Assert(), SERIALIZABLEXACT::commitSeqNo, CreateLocalPredicateLockHash(), CreatePredXact(), dlist_iter::cur, dlist_container, dlist_foreach, dlist_init(), dlist_is_empty(), dlist_node_init(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, SERIALIZABLEXACT::flags, GET_VXID_FROM_PGPROC, GetSnapshotData(), GetTopTransactionIdIfAny(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, InvalidSerializableXact, InvalidTransactionId, IsInParallelMode(), SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), max_prepared_xacts, MaxBackends, MyProc, MyProcNumber, MyProcPid, MySerializableXact, MyXactDidWrite, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::pgprocno, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::predicateLocks, PredXact, SERIALIZABLEXACT::prepareSeqNo, ProcArrayInstallImportedXmin(), RecoveryInProgress(), ReleasePredXact(), SERIALIZABLEXACT::SeqNo, SerialSetActiveSerXmin(), SetPossibleUnsafeConflict(), SummarizeOldestCommittedSxact(), SXACT_FLAG_READ_ONLY, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactIsCommitted, SxactIsDoomed, SxactIsReadOnly, SERIALIZABLEXACT::topXid, TransactionIdEquals, TransactionIdFollows(), TransactionIdIsValid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, XactReadOnly, SERIALIZABLEXACT::xmin, and SnapshotData::xmin.

Referenced by GetSafeSnapshot(), GetSerializableTransactionSnapshot(), and SetSerializableTransactionSnapshot().

◆ MaxPredicateChildLocks()

static int MaxPredicateChildLocks ( const PREDICATELOCKTARGETTAG tag)
static

Definition at line 2287 of file predicate.c.

2288{
2289 switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2290 {
2296
2297 case PREDLOCKTAG_PAGE:
2299
2300 case PREDLOCKTAG_TUPLE:
2301
2302 /*
2303 * not reachable: nothing is finer-granularity than a tuple, so we
2304 * should never try to promote to it.
2305 */
2306 Assert(false);
2307 return 0;
2308 }
2309
2310 /* not reachable */
2311 Assert(false);
2312 return 0;
2313}
int max_predicate_locks_per_page
Definition: predicate.c:373
int max_predicate_locks_per_relation
Definition: predicate.c:372

References Assert(), GET_PREDICATELOCKTARGETTAG_TYPE, max_predicate_locks_per_page, max_predicate_locks_per_relation, max_predicate_locks_per_xact, PREDLOCKTAG_PAGE, PREDLOCKTAG_RELATION, and PREDLOCKTAG_TUPLE.

Referenced by CheckAndPromotePredicateLockRequest().

◆ OnConflict_CheckForSerializationFailure()

static void OnConflict_CheckForSerializationFailure ( const SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4534 of file predicate.c.

4536{
4537 bool failure;
4538
4539 Assert(LWLockHeldByMe(SerializableXactHashLock));
4540
4541 failure = false;
4542
4543 /*------------------------------------------------------------------------
4544 * Check for already-committed writer with rw-conflict out flagged
4545 * (conflict-flag on W means that T2 committed before W):
4546 *
4547 * R ------> W ------> T2
4548 * rw rw
4549 *
4550 * That is a dangerous structure, so we must abort. (Since the writer
4551 * has already committed, we must be the reader)
4552 *------------------------------------------------------------------------
4553 */
4554 if (SxactIsCommitted(writer)
4555 && (SxactHasConflictOut(writer) || SxactHasSummaryConflictOut(writer)))
4556 failure = true;
4557
4558 /*------------------------------------------------------------------------
4559 * Check whether the writer has become a pivot with an out-conflict
4560 * committed transaction (T2), and T2 committed first:
4561 *
4562 * R ------> W ------> T2
4563 * rw rw
4564 *
4565 * Because T2 must've committed first, there is no anomaly if:
4566 * - the reader committed before T2
4567 * - the writer committed before T2
4568 * - the reader is a READ ONLY transaction and the reader was concurrent
4569 * with T2 (= reader acquired its snapshot before T2 committed)
4570 *
4571 * We also handle the case that T2 is prepared but not yet committed
4572 * here. In that case T2 has already checked for conflicts, so if it
4573 * commits first, making the above conflict real, it's too late for it
4574 * to abort.
4575 *------------------------------------------------------------------------
4576 */
4577 if (!failure && SxactHasSummaryConflictOut(writer))
4578 failure = true;
4579 else if (!failure)
4580 {
4581 dlist_iter iter;
4582
4583 dlist_foreach(iter, &writer->outConflicts)
4584 {
4585 RWConflict conflict =
4586 dlist_container(RWConflictData, outLink, iter.cur);
4587 SERIALIZABLEXACT *t2 = conflict->sxactIn;
4588
4589 if (SxactIsPrepared(t2)
4590 && (!SxactIsCommitted(reader)
4591 || t2->prepareSeqNo <= reader->commitSeqNo)
4592 && (!SxactIsCommitted(writer)
4593 || t2->prepareSeqNo <= writer->commitSeqNo)
4594 && (!SxactIsReadOnly(reader)
4595 || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
4596 {
4597 failure = true;
4598 break;
4599 }
4600 }
4601 }
4602
4603 /*------------------------------------------------------------------------
4604 * Check whether the reader has become a pivot with a writer
4605 * that's committed (or prepared):
4606 *
4607 * T0 ------> R ------> W
4608 * rw rw
4609 *
4610 * Because W must've committed first for an anomaly to occur, there is no
4611 * anomaly if:
4612 * - T0 committed before the writer
4613 * - T0 is READ ONLY, and overlaps the writer
4614 *------------------------------------------------------------------------
4615 */
4616 if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
4617 {
4618 if (SxactHasSummaryConflictIn(reader))
4619 {
4620 failure = true;
4621 }
4622 else
4623 {
4624 dlist_iter iter;
4625
4626 /*
4627 * The unconstify is needed as we have no const version of
4628 * dlist_foreach().
4629 */
4630 dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->inConflicts)
4631 {
4632 const RWConflict conflict =
4633 dlist_container(RWConflictData, inLink, iter.cur);
4634 const SERIALIZABLEXACT *t0 = conflict->sxactOut;
4635
4636 if (!SxactIsDoomed(t0)
4637 && (!SxactIsCommitted(t0)
4638 || t0->commitSeqNo >= writer->prepareSeqNo)
4639 && (!SxactIsReadOnly(t0)
4640 || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
4641 {
4642 failure = true;
4643 break;
4644 }
4645 }
4646 }
4647 }
4648
4649 if (failure)
4650 {
4651 /*
4652 * We have to kill a transaction to avoid a possible anomaly from
4653 * occurring. If the writer is us, we can just ereport() to cause a
4654 * transaction abort. Otherwise we flag the writer for termination,
4655 * causing it to abort when it tries to commit. However, if the writer
4656 * is a prepared transaction, already prepared, we can't abort it
4657 * anymore, so we have to kill the reader instead.
4658 */
4659 if (MySerializableXact == writer)
4660 {
4661 LWLockRelease(SerializableXactHashLock);
4662 ereport(ERROR,
4664 errmsg("could not serialize access due to read/write dependencies among transactions"),
4665 errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
4666 errhint("The transaction might succeed if retried.")));
4667 }
4668 else if (SxactIsPrepared(writer))
4669 {
4670 LWLockRelease(SerializableXactHashLock);
4671
4672 /* if we're not the writer, we have to be the reader */
4673 Assert(MySerializableXact == reader);
4674 ereport(ERROR,
4676 errmsg("could not serialize access due to read/write dependencies among transactions"),
4677 errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
4678 errhint("The transaction might succeed if retried.")));
4679 }
4680 writer->flags |= SXACT_FLAG_DOOMED;
4681 }
4682}
#define unconstify(underlying_type, expr)
Definition: c.h:1243

References Assert(), SERIALIZABLEXACT::commitSeqNo, dlist_iter::cur, dlist_container, dlist_foreach, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LWLockHeldByMe(), LWLockRelease(), MySerializableXact, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::prepareSeqNo, SERIALIZABLEXACT::SeqNo, SXACT_FLAG_DOOMED, SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, RWConflictData::sxactIn, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, RWConflictData::sxactOut, SERIALIZABLEXACT::topXid, and unconstify.

Referenced by FlagRWConflict().

◆ PageIsPredicateLocked()

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

Definition at line 2006 of file predicate.c.

2007{
2008 PREDICATELOCKTARGETTAG targettag;
2009 uint32 targettaghash;
2010 LWLock *partitionLock;
2011 PREDICATELOCKTARGET *target;
2012
2014 relation->rd_locator.dbOid,
2015 relation->rd_id,
2016 blkno);
2017
2018 targettaghash = PredicateLockTargetTagHashCode(&targettag);
2019 partitionLock = PredicateLockHashPartitionLock(targettaghash);
2020 LWLockAcquire(partitionLock, LW_SHARED);
2021 target = (PREDICATELOCKTARGET *)
2023 &targettag, targettaghash,
2024 HASH_FIND, NULL);
2025 LWLockRelease(partitionLock);
2026
2027 return (target != NULL);
2028}

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

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

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

static uint32 predicatelock_hash ( const void *  key,
Size  keysize 
)
static

Definition at line 1419 of file predicate.c.

1420{
1421 const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
1422 uint32 targethash;
1423
1424 Assert(keysize == sizeof(PREDICATELOCKTAG));
1425
1426 /* Look into the associated target object, and compute its hash code */
1427 targethash = PredicateLockTargetTagHashCode(&predicatelocktag->myTarget->tag);
1428
1429 return PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash);
1430}

References Assert(), sort-test::key, PREDICATELOCKTAG::myTarget, PredicateLockHashCodeFromTargetHashCode, PredicateLockTargetTagHashCode, and PREDICATELOCKTARGET::tag.

Referenced by PredicateLockShmemInit().

◆ predicatelock_twophase_recover()

void predicatelock_twophase_recover ( FullTransactionId  fxid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 4907 of file predicate.c.

4909{
4912
4914
4915 record = (TwoPhasePredicateRecord *) recdata;
4916
4918 (record->type == TWOPHASEPREDICATERECORD_LOCK));
4919
4920 if (record->type == TWOPHASEPREDICATERECORD_XACT)
4921 {
4922 /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4923 TwoPhasePredicateXactRecord *xactRecord;
4924 SERIALIZABLEXACT *sxact;
4925 SERIALIZABLEXID *sxid;
4926 SERIALIZABLEXIDTAG sxidtag;
4927 bool found;
4928
4929 xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4930
4931 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4932 sxact = CreatePredXact();
4933 if (!sxact)
4934 ereport(ERROR,
4935 (errcode(ERRCODE_OUT_OF_MEMORY),
4936 errmsg("out of shared memory")));
4937
4938 /* vxid for a prepared xact is INVALID_PROC_NUMBER/xid; no pid */
4941 sxact->pid = 0;
4943
4944 /* a prepared xact hasn't committed yet */
4948
4950
4951 /*
4952 * Don't need to track this; no transactions running at the time the
4953 * recovered xact started are still active, except possibly other
4954 * prepared xacts and we don't care whether those are RO_SAFE or not.
4955 */
4957
4958 dlist_init(&(sxact->predicateLocks));
4960
4961 sxact->topXid = xid;
4962 sxact->xmin = xactRecord->xmin;
4963 sxact->flags = xactRecord->flags;
4964 Assert(SxactIsPrepared(sxact));
4965 if (!SxactIsReadOnly(sxact))
4966 {
4970 }
4971
4972 /*
4973 * We don't know whether the transaction had any conflicts or not, so
4974 * we'll conservatively assume that it had both a conflict in and a
4975 * conflict out, and represent that with the summary conflict flags.
4976 */
4977 dlist_init(&(sxact->outConflicts));
4978 dlist_init(&(sxact->inConflicts));
4981
4982 /* Register the transaction's xid */
4983 sxidtag.xid = xid;
4985 &sxidtag,
4986 HASH_ENTER, &found);
4987 Assert(sxid != NULL);
4988 Assert(!found);
4989 sxid->myXact = sxact;
4990
4991 /*
4992 * Update global xmin. Note that this is a special case compared to
4993 * registering a normal transaction, because the global xmin might go
4994 * backwards. That's OK, because until recovery is over we're not
4995 * going to complete any transactions or create any non-prepared
4996 * transactions, so there's no danger of throwing away.
4997 */
5000 {
5001 PredXact->SxactGlobalXmin = sxact->xmin;
5004 }
5006 {
5009 }
5010
5011 LWLockRelease(SerializableXactHashLock);
5012 }
5013 else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
5014 {
5015 /* Lock record. Recreate the PREDICATELOCK */
5016 TwoPhasePredicateLockRecord *lockRecord;
5017 SERIALIZABLEXID *sxid;
5018 SERIALIZABLEXACT *sxact;
5019 SERIALIZABLEXIDTAG sxidtag;
5020 uint32 targettaghash;
5021
5022 lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
5023 targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
5024
5025 LWLockAcquire(SerializableXactHashLock, LW_SHARED);
5026 sxidtag.xid = xid;
5027 sxid = (SERIALIZABLEXID *)
5028 hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
5029 LWLockRelease(SerializableXactHashLock);
5030
5031 Assert(sxid != NULL);
5032 sxact = sxid->myXact;
5034
5035 CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
5036 }
5037}
uint32 LocalTransactionId
Definition: c.h:673
uint32 TransactionId
Definition: c.h:671
const void size_t len
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2451
#define RecoverySerCommitSeqNo
LocalTransactionId localTransactionId
Definition: lock.h:64
ProcNumber procNumber
Definition: lock.h:63
#define XidFromFullTransactionId(x)
Definition: transam.h:48

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, XidFromFullTransactionId, SERIALIZABLEXACT::xmin, and TwoPhasePredicateXactRecord::xmin.

◆ PredicateLockAcquire()

static void PredicateLockAcquire ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2515 of file predicate.c.

2516{
2517 uint32 targettaghash;
2518 bool found;
2519 LOCALPREDICATELOCK *locallock;
2520
2521 /* Do we have the lock already, or a covering lock? */
2522 if (PredicateLockExists(targettag))
2523 return;
2524
2525 if (CoarserLockCovers(targettag))
2526 return;
2527
2528 /* the same hash and LW lock apply to the lock target and the local lock. */
2529 targettaghash = PredicateLockTargetTagHashCode(targettag);
2530
2531 /* Acquire lock in local table */
2532 locallock = (LOCALPREDICATELOCK *)
2534 targettag, targettaghash,
2535 HASH_ENTER, &found);
2536 locallock->held = true;
2537 if (!found)
2538 locallock->childLocks = 0;
2539
2540 /* Actually create the lock */
2541 CreatePredicateLock(targettag, targettaghash, MySerializableXact);
2542
2543 /*
2544 * Lock has been acquired. Check whether it should be promoted to a
2545 * coarser granularity, or whether there are finer-granularity locks to
2546 * clean up.
2547 */
2549 {
2550 /*
2551 * Lock request was promoted to a coarser-granularity lock, and that
2552 * lock was acquired. It will delete this lock and any of its
2553 * children, so we're done.
2554 */
2555 }
2556 else
2557 {
2558 /* Clean up any finer-granularity locks */
2560 DeleteChildTargetLocks(targettag);
2561 }
2562}
static void DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
Definition: predicate.c:2212
static bool CheckAndPromotePredicateLockRequest(const PREDICATELOCKTARGETTAG *reqtag)
Definition: predicate.c:2324
static bool CoarserLockCovers(const PREDICATELOCKTARGETTAG *newtargettag)
Definition: predicate.c:2109

References CheckAndPromotePredicateLockRequest(), LOCALPREDICATELOCK::childLocks, CoarserLockCovers(), CreatePredicateLock(), DeleteChildTargetLocks(), GET_PREDICATELOCKTARGETTAG_TYPE, HASH_ENTER, hash_search_with_hash_value(), LOCALPREDICATELOCK::held, LocalPredicateLockHash, MySerializableXact, PredicateLockExists(), PredicateLockTargetTagHashCode, and PREDLOCKTAG_TUPLE.

Referenced by CheckAndPromotePredicateLockRequest(), PredicateLockPage(), PredicateLockRelation(), and PredicateLockTID().

◆ PredicateLockExists()

static bool PredicateLockExists ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2043 of file predicate.c.

2044{
2045 LOCALPREDICATELOCK *lock;
2046
2047 /* check local hash table */
2049 targettag,
2050 HASH_FIND, NULL);
2051
2052 if (!lock)
2053 return false;
2054
2055 /*
2056 * Found entry in the table, but still need to check whether it's actually
2057 * held -- it could just be a parent of some held lock.
2058 */
2059 return lock->held;
2060}

References HASH_FIND, hash_search(), LOCALPREDICATELOCK::held, and LocalPredicateLockHash.

Referenced by CoarserLockCovers(), PredicateLockAcquire(), and PredicateLockTID().

◆ PredicateLockingNeededForRelation()

static bool PredicateLockingNeededForRelation ( Relation  relation)
inlinestatic

Definition at line 498 of file predicate.c.

499{
500 return !(relation->rd_id < FirstUnpinnedObjectId ||
501 RelationUsesLocalBuffers(relation));
502}
#define RelationUsesLocalBuffers(relation)
Definition: rel.h:647
#define FirstUnpinnedObjectId
Definition: transam.h:196

References FirstUnpinnedObjectId, RelationData::rd_id, and RelationUsesLocalBuffers.

Referenced by DropAllPredicateLocksFromTable(), PredicateLockPageSplit(), SerializationNeededForRead(), and SerializationNeededForWrite().

◆ PredicateLockPage()

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

◆ PredicateLockPageCombine()

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

Definition at line 3227 of file predicate.c.

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

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

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

Definition at line 3142 of file predicate.c.

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

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 int64 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 {
1258 LWTRANCHE_PER_XACT_PREDICATE_LIST);
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:624
bool IsUnderPostmaster
Definition: globals.c:120
#define HASH_FUNCTION
Definition: hsearch.h:98
#define HASH_FIXED_SIZE
Definition: hsearch.h:105
#define HASH_PARTITION
Definition: hsearch.h:92
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:76
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:698
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 void SerialInit(void)
Definition: predicate.c:806
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 SERIALIZABLEXID SERIALIZABLEXID
struct RWConflictData * RWConflict
#define SXACT_FLAG_COMMITTED
struct PREDICATELOCK PREDICATELOCK
Size add_size(Size s1, Size s2)
Definition: shmem.c:495
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510
HTAB * ShmemInitHash(const char *name, int64 init_size, int64 max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:334
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:389
HashValueFunc hash
Definition: hsearch.h:78
int64 num_partitions
Definition: hsearch.h:68
SERIALIZABLEXACT * element
SERIALIZABLEXACT * OldCommittedSxact

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(), 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(int64 num_entries, Size entrysize)
Definition: dynahash.c:783
int serializable_buffers
Definition: globals.c:165
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,
const ItemPointerData tid,
Snapshot  snapshot,
TransactionId  tuple_xid 
)

Definition at line 2619 of file predicate.c.

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

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 ( FullTransactionId  fxid,
bool  isCommit 
)

Definition at line 4880 of file predicate.c.

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

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

Referenced by FinishPreparedTransaction().

◆ RegisterPredicateLockingXid()

void RegisterPredicateLockingXid ( TransactionId  xid)

Definition at line 1957 of file predicate.c.

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

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

◆ ReleaseOneSerializableXact()

static void ReleaseOneSerializableXact ( SERIALIZABLEXACT sxact,
bool  partial,
bool  summarize 
)
static

Definition at line 3833 of file predicate.c.

3835{
3836 SERIALIZABLEXIDTAG sxidtag;
3837 dlist_mutable_iter iter;
3838
3839 Assert(sxact != NULL);
3840 Assert(SxactIsRolledBack(sxact) || SxactIsCommitted(sxact));
3841 Assert(partial || !SxactIsOnFinishedList(sxact));
3842 Assert(LWLockHeldByMe(SerializableFinishedListLock));
3843
3844 /*
3845 * First release all the predicate locks held by this xact (or transfer
3846 * them to OldCommittedSxact if summarize is true)
3847 */
3848 LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
3849 if (IsInParallelMode())
3852 {
3853 PREDICATELOCK *predlock =
3854 dlist_container(PREDICATELOCK, xactLink, iter.cur);
3855 PREDICATELOCKTAG tag;
3856 PREDICATELOCKTARGET *target;
3857 PREDICATELOCKTARGETTAG targettag;
3858 uint32 targettaghash;
3859 LWLock *partitionLock;
3860
3861 tag = predlock->tag;
3862 target = tag.myTarget;
3863 targettag = target->tag;
3864 targettaghash = PredicateLockTargetTagHashCode(&targettag);
3865 partitionLock = PredicateLockHashPartitionLock(targettaghash);
3866
3867 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3868
3869 dlist_delete(&predlock->targetLink);
3870
3873 targettaghash),
3874 HASH_REMOVE, NULL);
3875 if (summarize)
3876 {
3877 bool found;
3878
3879 /* Fold into dummy transaction list. */
3883 targettaghash),
3884 HASH_ENTER_NULL, &found);
3885 if (!predlock)
3886 ereport(ERROR,
3887 (errcode(ERRCODE_OUT_OF_MEMORY),
3888 errmsg("out of shared memory"),
3889 errhint("You might need to increase \"%s\".", "max_pred_locks_per_transaction")));
3890 if (found)
3891 {
3892 Assert(predlock->commitSeqNo != 0);
3894 if (predlock->commitSeqNo < sxact->commitSeqNo)
3895 predlock->commitSeqNo = sxact->commitSeqNo;
3896 }
3897 else
3898 {
3900 &predlock->targetLink);
3902 &predlock->xactLink);
3903 predlock->commitSeqNo = sxact->commitSeqNo;
3904 }
3905 }
3906 else
3907 RemoveTargetIfNoLongerUsed(target, targettaghash);
3908
3909 LWLockRelease(partitionLock);
3910 }
3911
3912 /*
3913 * Rather than retail removal, just re-init the head after we've run
3914 * through the list.
3915 */
3916 dlist_init(&sxact->predicateLocks);
3917
3918 if (IsInParallelMode())
3920 LWLockRelease(SerializablePredicateListLock);
3921
3922 sxidtag.xid = sxact->topXid;
3923 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3924
3925 /* Release all outConflicts (unless 'partial' is true) */
3926 if (!partial)
3927 {
3928 dlist_foreach_modify(iter, &sxact->outConflicts)
3929 {
3930 RWConflict conflict =
3931 dlist_container(RWConflictData, outLink, iter.cur);
3932
3933 if (summarize)
3935 ReleaseRWConflict(conflict);
3936 }
3937 }
3938
3939 /* Release all inConflicts. */
3940 dlist_foreach_modify(iter, &sxact->inConflicts)
3941 {
3942 RWConflict conflict =
3943 dlist_container(RWConflictData, inLink, iter.cur);
3944
3945 if (summarize)
3947 ReleaseRWConflict(conflict);
3948 }
3949
3950 /* Finally, get rid of the xid and the record of the transaction itself. */
3951 if (!partial)
3952 {
3953 if (sxidtag.xid != InvalidTransactionId)
3955 ReleasePredXact(sxact);
3956 }
3957
3958 LWLockRelease(SerializableXactHashLock);
3959}
#define SxactIsOnFinishedList(sxact)
Definition: predicate.c:267
#define SxactIsRolledBack(sxact)
Definition: predicate.c:279

References Assert(), SERIALIZABLEXACT::commitSeqNo, PREDICATELOCK::commitSeqNo, dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_foreach_modify, dlist_init(), dlist_push_tail(), ereport, errcode(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, HASH_ENTER_NULL, HASH_REMOVE, hash_search(), hash_search_with_hash_value(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, InvalidTransactionId, IsInParallelMode(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, OldCommittedSxact, SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::perXactPredicateListLock, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetTagHashCode, ReleasePredXact(), ReleaseRWConflict(), RemoveTargetIfNoLongerUsed(), SerializableXidHash, SXACT_FLAG_SUMMARY_CONFLICT_IN, SXACT_FLAG_SUMMARY_CONFLICT_OUT, RWConflictData::sxactIn, SxactIsCommitted, SxactIsOnFinishedList, SxactIsRolledBack, RWConflictData::sxactOut, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, SERIALIZABLEXACT::topXid, PREDICATELOCK::xactLink, and SERIALIZABLEXIDTAG::xid.

Referenced by ClearOldPredicateLocks(), ReleasePredicateLocks(), and SummarizeOldestCommittedSxact().

◆ ReleasePredicateLocks()

void ReleasePredicateLocks ( bool  isCommit,
bool  isReadOnlySafe 
)

Definition at line 3310 of file predicate.c.

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

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

◆ ReleasePredicateLocksLocal()

static void ReleasePredicateLocksLocal ( void  )
static

Definition at line 3677 of file predicate.c.

3678{
3680 MyXactDidWrite = false;
3681
3682 /* Delete per-transaction lock table */
3683 if (LocalPredicateLockHash != NULL)
3684 {
3687 }
3688}

References hash_destroy(), InvalidSerializableXact, LocalPredicateLockHash, MySerializableXact, and MyXactDidWrite.

Referenced by ReleasePredicateLocks().

◆ ReleasePredXact()

static void ReleasePredXact ( SERIALIZABLEXACT sxact)
static

◆ ReleaseRWConflict()

static void ReleaseRWConflict ( RWConflict  conflict)
static

◆ RemoveScratchTarget()

static void RemoveScratchTarget ( bool  lockheld)
static

◆ RemoveTargetIfNoLongerUsed()

static void RemoveTargetIfNoLongerUsed ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

Definition at line 2181 of file predicate.c.

2182{
2184
2185 Assert(LWLockHeldByMe(SerializablePredicateListLock));
2186
2187 /* Can't remove it until no locks at this target. */
2188 if (!dlist_is_empty(&target->predicateLocks))
2189 return;
2190
2191 /* Actually remove the target. */
2193 &target->tag,
2194 targettaghash,
2195 HASH_REMOVE, NULL);
2196 Assert(rmtarget == target);
2197}

References Assert(), dlist_is_empty(), HASH_REMOVE, hash_search_with_hash_value(), LWLockHeldByMe(), PG_USED_FOR_ASSERTS_ONLY, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, and PREDICATELOCKTARGET::tag.

Referenced by CheckTargetForConflictsIn(), ClearOldPredicateLocks(), DeleteChildTargetLocks(), DeleteLockTarget(), ReleaseOneSerializableXact(), and TransferPredicateLocksToNewTarget().

◆ RestoreScratchTarget()

static void RestoreScratchTarget ( bool  lockheld)
static

◆ RWConflictExists()

static bool RWConflictExists ( const SERIALIZABLEXACT reader,
const SERIALIZABLEXACT writer 
)
static

Definition at line 610 of file predicate.c.

611{
612 dlist_iter iter;
613
614 Assert(reader != writer);
615
616 /* Check the ends of the purported conflict first. */
617 if (SxactIsDoomed(reader)
618 || SxactIsDoomed(writer)
619 || dlist_is_empty(&reader->outConflicts)
620 || dlist_is_empty(&writer->inConflicts))
621 return false;
622
623 /*
624 * A conflict is possible; walk the list to find out.
625 *
626 * The unconstify is needed as we have no const version of
627 * dlist_foreach().
628 */
629 dlist_foreach(iter, &unconstify(SERIALIZABLEXACT *, reader)->outConflicts)
630 {
631 RWConflict conflict =
632 dlist_container(RWConflictData, outLink, iter.cur);
633
634 if (conflict->sxactIn == writer)
635 return true;
636 }
637
638 /* No conflict found. */
639 return false;
640}

References Assert(), dlist_iter::cur, dlist_container, dlist_foreach, dlist_is_empty(), SERIALIZABLEXACT::inConflicts, SERIALIZABLEXACT::outConflicts, RWConflictData::sxactIn, SxactIsDoomed, and unconstify.

Referenced by CheckForSerializableConflictOut(), CheckTableForSerializableConflictIn(), CheckTargetForConflictsIn(), and SetRWConflict().

◆ SerialAdd()

static void SerialAdd ( TransactionId  xid,
SerCommitSeqNo  minConflictCommitSeqNo 
)
static

Definition at line 858 of file predicate.c.

859{
860 TransactionId tailXid;
861 int64 targetPage;
862 int slotno;
863 int64 firstZeroPage;
864 bool isNewPage;
865 LWLock *lock;
866
868
869 targetPage = SerialPage(xid);
870 lock = SimpleLruGetBankLock(SerialSlruCtl, targetPage);
871
872 /*
873 * In this routine, we must hold both SerialControlLock and the SLRU bank
874 * lock simultaneously while making the SLRU data catch up with the new
875 * state that we determine.
876 */
877 LWLockAcquire(SerialControlLock, LW_EXCLUSIVE);
878
879 /*
880 * If 'xid' is older than the global xmin (== tailXid), there's no need to
881 * store it, after all. This can happen if the oldest transaction holding
882 * back the global xmin just finished, making 'xid' uninteresting, but
883 * ClearOldPredicateLocks() has not yet run.
884 */
885 tailXid = serialControl->tailXid;
886 if (!TransactionIdIsValid(tailXid) || TransactionIdPrecedes(xid, tailXid))
887 {
888 LWLockRelease(SerialControlLock);
889 return;
890 }
891
892 /*
893 * If the SLRU is currently unused, zero out the whole active region from
894 * tailXid to headXid before taking it into use. Otherwise zero out only
895 * any new pages that enter the tailXid-headXid range as we advance
896 * headXid.
897 */
898 if (serialControl->headPage < 0)
899 {
900 firstZeroPage = SerialPage(tailXid);
901 isNewPage = true;
902 }
903 else
904 {
905 firstZeroPage = SerialNextPage(serialControl->headPage);
907 targetPage);
908 }
909
912 serialControl->headXid = xid;
913 if (isNewPage)
914 serialControl->headPage = targetPage;
915
916 if (isNewPage)
917 {
918 /* Initialize intervening pages; might involve trading locks */
919 for (;;)
920 {
921 lock = SimpleLruGetBankLock(SerialSlruCtl, firstZeroPage);
923 slotno = SimpleLruZeroPage(SerialSlruCtl, firstZeroPage);
924 if (firstZeroPage == targetPage)
925 break;
926 firstZeroPage = SerialNextPage(firstZeroPage);
927 LWLockRelease(lock);
928 }
929 }
930 else
931 {
933 slotno = SimpleLruReadPage(SerialSlruCtl, targetPage, true, xid);
934 }
935
936 SerialValue(slotno, xid) = minConflictCommitSeqNo;
937 SerialSlruCtl->shared->page_dirty[slotno] = true;
938
939 LWLockRelease(lock);
940 LWLockRelease(SerialControlLock);
941}
#define SerialNextPage(page)
Definition: predicate.c:337
#define SerialValue(slotno, xid)
Definition: predicate.c:339
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition: slru.c:527
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:375
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:160
TransactionId headXid
Definition: predicate.c:348

References Assert(), SerialControlData::headPage, SerialControlData::headXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), serialControl, SerialNextPage, SerialPage, SerialPagePrecedesLogically(), SerialSlruCtl, SerialValue, SimpleLruGetBankLock(), SimpleLruReadPage(), SimpleLruZeroPage(), SerialControlData::tailXid, TransactionIdFollows(), TransactionIdIsValid, and TransactionIdPrecedes().

Referenced by SummarizeOldestCommittedSxact().

◆ SerialGetMinConflictCommitSeqNo()

static SerCommitSeqNo SerialGetMinConflictCommitSeqNo ( TransactionId  xid)
static

Definition at line 949 of file predicate.c.

950{
951 TransactionId headXid;
952 TransactionId tailXid;
954 int slotno;
955
957
958 LWLockAcquire(SerialControlLock, LW_SHARED);
959 headXid = serialControl->headXid;
960 tailXid = serialControl->tailXid;
961 LWLockRelease(SerialControlLock);
962
963 if (!TransactionIdIsValid(headXid))
964 return 0;
965
967
968 if (TransactionIdPrecedes(xid, tailXid)
969 || TransactionIdFollows(xid, headXid))
970 return 0;
971
972 /*
973 * The following function must be called without holding SLRU bank lock,
974 * but will return with that lock held, which must then be released.
975 */
977 SerialPage(xid), xid);
978 val = SerialValue(slotno, xid);
980 return val;
981}
long val
Definition: informix.c:689
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:630

References Assert(), SerialControlData::headXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), serialControl, SerialPage, SerialSlruCtl, SerialValue, SimpleLruGetBankLock(), SimpleLruReadPage_ReadOnly(), SerialControlData::tailXid, TransactionIdFollows(), TransactionIdIsValid, TransactionIdPrecedes(), and val.

Referenced by CheckForSerializableConflictOut().

◆ SerialInit()

static void SerialInit ( void  )
static

Definition at line 806 of file predicate.c.

807{
808 bool found;
809
810 /*
811 * Set up SLRU management of the pg_serial data.
812 */
814 SimpleLruInit(SerialSlruCtl, "serializable",
815 serializable_buffers, 0, "pg_serial",
816 LWTRANCHE_SERIAL_BUFFER, LWTRANCHE_SERIAL_SLRU,
817 SYNC_HANDLER_NONE, false);
818#ifdef USE_ASSERT_CHECKING
819 SerialPagePrecedesLogicallyUnitTests();
820#endif
822
823 /*
824 * Create or attach to the SerialControl structure.
825 */
827 ShmemInitStruct("SerialControlData", sizeof(SerialControlData), &found);
828
829 Assert(found == IsUnderPostmaster);
830 if (!found)
831 {
832 /*
833 * Set control information to reflect empty SLRU.
834 */
835 LWLockAcquire(SerialControlLock, LW_EXCLUSIVE);
839 LWLockRelease(SerialControlLock);
840 }
841}
struct SerialControlData * SerialControl
Definition: predicate.c:352
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, const char *subdir, int buffer_tranche_id, int bank_tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
Definition: slru.c:252
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:185
@ SYNC_HANDLER_NONE
Definition: sync.h:42

References Assert(), SerialControlData::headPage, SerialControlData::headXid, InvalidTransactionId, IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SERIAL_ENTRIESPERPAGE, serialControl, serializable_buffers, SerialPagePrecedesLogically(), SerialSlruCtl, ShmemInitStruct(), SimpleLruInit(), SlruPagePrecedesUnitTests, SYNC_HANDLER_NONE, and SerialControlData::tailXid.

Referenced by PredicateLockShmemInit().

◆ SerializationNeededForRead()

static bool SerializationNeededForRead ( Relation  relation,
Snapshot  snapshot 
)
inlinestatic

Definition at line 516 of file predicate.c.

517{
518 /* Nothing to do if this is not a serializable transaction */
520 return false;
521
522 /*
523 * Don't acquire locks or conflict when scanning with a special snapshot.
524 * This excludes things like CLUSTER and REINDEX. They use the wholesale
525 * functions TransferPredicateLocksToHeapRelation() and
526 * CheckTableForSerializableConflictIn() to participate in serialization,
527 * but the scans involved don't need serialization.
528 */
529 if (!IsMVCCSnapshot(snapshot))
530 return false;
531
532 /*
533 * Check if we have just become "RO-safe". If we have, immediately release
534 * all locks as they're not needed anymore. This also resets
535 * MySerializableXact, so that subsequent calls to this function can exit
536 * quickly.
537 *
538 * A transaction is flagged as RO_SAFE if all concurrent R/W transactions
539 * commit without having conflicts out to an earlier snapshot, thus
540 * ensuring that no conflicts are possible for this transaction.
541 */
543 {
544 ReleasePredicateLocks(false, true);
545 return false;
546 }
547
548 /* Check if the relation doesn't participate in predicate locking */
550 return false;
551
552 return true; /* no excuse to skip predicate locking */
553}
#define IsMVCCSnapshot(snapshot)
Definition: snapmgr.h:55

References InvalidSerializableXact, IsMVCCSnapshot, MySerializableXact, PredicateLockingNeededForRelation(), ReleasePredicateLocks(), and SxactIsROSafe.

Referenced by CheckForSerializableConflictOut(), CheckForSerializableConflictOutNeeded(), PredicateLockPage(), PredicateLockRelation(), and PredicateLockTID().

◆ SerializationNeededForWrite()

static bool SerializationNeededForWrite ( Relation  relation)
inlinestatic

Definition at line 560 of file predicate.c.

561{
562 /* Nothing to do if this is not a serializable transaction */
564 return false;
565
566 /* Check if the relation doesn't participate in predicate locking */
568 return false;
569
570 return true; /* no excuse to skip predicate locking */
571}

References InvalidSerializableXact, MySerializableXact, and PredicateLockingNeededForRelation().

Referenced by CheckForSerializableConflictIn(), and CheckTableForSerializableConflictIn().

◆ SerialPagePrecedesLogically()

static bool SerialPagePrecedesLogically ( int64  page1,
int64  page2 
)
static

Definition at line 731 of file predicate.c.

732{
733 TransactionId xid1;
734 TransactionId xid2;
735
736 xid1 = ((TransactionId) page1) * SERIAL_ENTRIESPERPAGE;
737 xid1 += FirstNormalTransactionId + 1;
738 xid2 = ((TransactionId) page2) * SERIAL_ENTRIESPERPAGE;
739 xid2 += FirstNormalTransactionId + 1;
740
741 return (TransactionIdPrecedes(xid1, xid2) &&
743}
#define FirstNormalTransactionId
Definition: transam.h:34

References FirstNormalTransactionId, SERIAL_ENTRIESPERPAGE, and TransactionIdPrecedes().

Referenced by CheckPointPredicate(), SerialAdd(), and SerialInit().

◆ SerialSetActiveSerXmin()

static void SerialSetActiveSerXmin ( TransactionId  xid)
static

Definition at line 990 of file predicate.c.

991{
992 LWLockAcquire(SerialControlLock, LW_EXCLUSIVE);
993
994 /*
995 * When no sxacts are active, nothing overlaps, set the xid values to
996 * invalid to show that there are no valid entries. Don't clear headPage,
997 * though. A new xmin might still land on that page, and we don't want to
998 * repeatedly zero out the same page.
999 */
1000 if (!TransactionIdIsValid(xid))
1001 {
1004 LWLockRelease(SerialControlLock);
1005 return;
1006 }
1007
1008 /*
1009 * When we're recovering prepared transactions, the global xmin might move
1010 * backwards depending on the order they're recovered. Normally that's not
1011 * OK, but during recovery no serializable transactions will commit, so
1012 * the SLRU is empty and we can get away with it.
1013 */
1014 if (RecoveryInProgress())
1015 {
1019 {
1020 serialControl->tailXid = xid;
1021 }
1022 LWLockRelease(SerialControlLock);
1023 return;
1024 }
1025
1028
1029 serialControl->tailXid = xid;
1030
1031 LWLockRelease(SerialControlLock);
1032}

References Assert(), SerialControlData::headPage, SerialControlData::headXid, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), RecoveryInProgress(), serialControl, SerialControlData::tailXid, TransactionIdFollows(), TransactionIdIsValid, and TransactionIdPrecedes().

Referenced by GetSerializableTransactionSnapshotInt(), predicatelock_twophase_recover(), and SetNewSxactGlobalXmin().

◆ SetNewSxactGlobalXmin()

◆ SetPossibleUnsafeConflict()

static void SetPossibleUnsafeConflict ( SERIALIZABLEXACT roXact,
SERIALIZABLEXACT activeXact 
)
static

Definition at line 666 of file predicate.c.

668{
669 RWConflict conflict;
670
671 Assert(roXact != activeXact);
672 Assert(SxactIsReadOnly(roXact));
673 Assert(!SxactIsReadOnly(activeXact));
674
677 (errcode(ERRCODE_OUT_OF_MEMORY),
678 errmsg("not enough elements in RWConflictPool to record a potential read/write conflict"),
679 errhint("You might need to run fewer transactions at a time or increase \"max_connections\".")));
680
682 dlist_delete(&conflict->outLink);
683
684 conflict->sxactOut = activeXact;
685 conflict->sxactIn = roXact;
686 dlist_push_tail(&activeXact->possibleUnsafeConflicts, &conflict->outLink);
687 dlist_push_tail(&roXact->possibleUnsafeConflicts, &conflict->inLink);
688}
#define dlist_head_element(type, membername, lhead)
Definition: ilist.h:603

References Assert(), RWConflictPoolHeaderData::availableList, dlist_delete(), dlist_head_element, dlist_is_empty(), dlist_push_tail(), ereport, errcode(), errhint(), errmsg(), ERROR, RWConflictData::inLink, RWConflictData::outLink, SERIALIZABLEXACT::possibleUnsafeConflicts, RWConflictPool, RWConflictData::sxactIn, SxactIsReadOnly, and RWConflictData::sxactOut.

Referenced by GetSerializableTransactionSnapshotInt().

◆ SetRWConflict()

static void SetRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 643 of file predicate.c.

644{
645 RWConflict conflict;
646
647 Assert(reader != writer);
648 Assert(!RWConflictExists(reader, writer));
649
652 (errcode(ERRCODE_OUT_OF_MEMORY),
653 errmsg("not enough elements in RWConflictPool to record a read/write conflict"),
654 errhint("You might need to run fewer transactions at a time or increase \"max_connections\".")));
655
657 dlist_delete(&conflict->outLink);
658
659 conflict->sxactOut = reader;
660 conflict->sxactIn = writer;
661 dlist_push_tail(&reader->outConflicts, &conflict->outLink);
662 dlist_push_tail(&writer->inConflicts, &conflict->inLink);
663}

References Assert(), RWConflictPoolHeaderData::availableList, dlist_delete(), dlist_head_element, dlist_is_empty(), dlist_push_tail(), ereport, errcode(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, RWConflictExists(), RWConflictPool, RWConflictData::sxactIn, and RWConflictData::sxactOut.

Referenced by FlagRWConflict().

◆ SetSerializableTransactionSnapshot()

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

Definition at line 1720 of file predicate.c.

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

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

Referenced by SetTransactionSnapshot().

◆ ShareSerializableXact()

SerializableXactHandle ShareSerializableXact ( void  )

Definition at line 5045 of file predicate.c.

5046{
5047 return MySerializableXact;
5048}

References MySerializableXact.

Referenced by InitializeParallelDSM().

◆ SummarizeOldestCommittedSxact()

static void SummarizeOldestCommittedSxact ( void  )
static

Definition at line 1501 of file predicate.c.

1502{
1503 SERIALIZABLEXACT *sxact;
1504
1505 LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
1506
1507 /*
1508 * This function is only called if there are no sxact slots available.
1509 * Some of them must belong to old, already-finished transactions, so
1510 * there should be something in FinishedSerializableTransactions list that
1511 * we can summarize. However, there's a race condition: while we were not
1512 * holding any locks, a transaction might have ended and cleaned up all
1513 * the finished sxact entries already, freeing up their sxact slots. In
1514 * that case, we have nothing to do here. The caller will find one of the
1515 * slots released by the other backend when it retries.
1516 */
1518 {
1519 LWLockRelease(SerializableFinishedListLock);
1520 return;
1521 }
1522
1523 /*
1524 * Grab the first sxact off the finished list -- this will be the earliest
1525 * commit. Remove it from the list.
1526 */
1527 sxact = dlist_head_element(SERIALIZABLEXACT, finishedLink,
1530
1531 /* Add to SLRU summary information. */
1532 if (TransactionIdIsValid(sxact->topXid) && !SxactIsReadOnly(sxact))
1533 SerialAdd(sxact->topXid, SxactHasConflictOut(sxact)
1535
1536 /* Summarize and release the detail. */
1537 ReleaseOneSerializableXact(sxact, false, true);
1538
1539 LWLockRelease(SerializableFinishedListLock);
1540}
static void SerialAdd(TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
Definition: predicate.c:858

References dlist_delete_thoroughly(), dlist_head_element, dlist_is_empty(), SERIALIZABLEXACT::earliestOutConflictCommit, SERIALIZABLEXACT::finishedLink, FinishedSerializableTransactions, InvalidSerCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), ReleaseOneSerializableXact(), SERIALIZABLEXACT::SeqNo, SerialAdd(), SxactHasConflictOut, SxactIsReadOnly, SERIALIZABLEXACT::topXid, and TransactionIdIsValid.

Referenced by GetSerializableTransactionSnapshotInt().

◆ TransferPredicateLocksToHeapRelation()

void TransferPredicateLocksToHeapRelation ( Relation  relation)

Definition at line 3121 of file predicate.c.

3122{
3123 DropAllPredicateLocksFromTable(relation, true);
3124}
static void DropAllPredicateLocksFromTable(Relation relation, bool transfer)
Definition: predicate.c:2935

References DropAllPredicateLocksFromTable().

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

◆ TransferPredicateLocksToNewTarget()

static bool TransferPredicateLocksToNewTarget ( PREDICATELOCKTARGETTAG  oldtargettag,
PREDICATELOCKTARGETTAG  newtargettag,
bool  removeOld 
)
static

Definition at line 2728 of file predicate.c.

2731{
2732 uint32 oldtargettaghash;
2733 LWLock *oldpartitionLock;
2734 PREDICATELOCKTARGET *oldtarget;
2735 uint32 newtargettaghash;
2736 LWLock *newpartitionLock;
2737 bool found;
2738 bool outOfShmem = false;
2739
2740 Assert(LWLockHeldByMeInMode(SerializablePredicateListLock,
2741 LW_EXCLUSIVE));
2742
2743 oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2744 newtargettaghash = PredicateLockTargetTagHashCode(&newtargettag);
2745 oldpartitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2746 newpartitionLock = PredicateLockHashPartitionLock(newtargettaghash);
2747
2748 if (removeOld)
2749 {
2750 /*
2751 * Remove the dummy entry to give us scratch space, so we know we'll
2752 * be able to create the new lock target.
2753 */
2754 RemoveScratchTarget(false);
2755 }
2756
2757 /*
2758 * We must get the partition locks in ascending sequence to avoid
2759 * deadlocks. If old and new partitions are the same, we must request the
2760 * lock only once.
2761 */
2762 if (oldpartitionLock < newpartitionLock)
2763 {
2764 LWLockAcquire(oldpartitionLock,
2765 (removeOld ? LW_EXCLUSIVE : LW_SHARED));
2766 LWLockAcquire(newpartitionLock, LW_EXCLUSIVE);
2767 }
2768 else if (oldpartitionLock > newpartitionLock)
2769 {
2770 LWLockAcquire(newpartitionLock, LW_EXCLUSIVE);
2771 LWLockAcquire(oldpartitionLock,
2772 (removeOld ? LW_EXCLUSIVE : LW_SHARED));
2773 }
2774 else
2775 LWLockAcquire(newpartitionLock, LW_EXCLUSIVE);
2776
2777 /*
2778 * Look for the old target. If not found, that's OK; no predicate locks
2779 * are affected, so we can just clean up and return. If it does exist,
2780 * walk its list of predicate locks and move or copy them to the new
2781 * target.
2782 */
2784 &oldtargettag,
2785 oldtargettaghash,
2786 HASH_FIND, NULL);
2787
2788 if (oldtarget)
2789 {
2790 PREDICATELOCKTARGET *newtarget;
2791 PREDICATELOCKTAG newpredlocktag;
2792 dlist_mutable_iter iter;
2793
2795 &newtargettag,
2796 newtargettaghash,
2797 HASH_ENTER_NULL, &found);
2798
2799 if (!newtarget)
2800 {
2801 /* Failed to allocate due to insufficient shmem */
2802 outOfShmem = true;
2803 goto exit;
2804 }
2805
2806 /* If we created a new entry, initialize it */
2807 if (!found)
2808 dlist_init(&newtarget->predicateLocks);
2809
2810 newpredlocktag.myTarget = newtarget;
2811
2812 /*
2813 * Loop through all the locks on the old target, replacing them with
2814 * locks on the new target.
2815 */
2816 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2817
2818 dlist_foreach_modify(iter, &oldtarget->predicateLocks)
2819 {
2820 PREDICATELOCK *oldpredlock =
2821 dlist_container(PREDICATELOCK, targetLink, iter.cur);
2822 PREDICATELOCK *newpredlock;
2823 SerCommitSeqNo oldCommitSeqNo = oldpredlock->commitSeqNo;
2824
2825 newpredlocktag.myXact = oldpredlock->tag.myXact;
2826
2827 if (removeOld)
2828 {
2829 dlist_delete(&(oldpredlock->xactLink));
2830 dlist_delete(&(oldpredlock->targetLink));
2831
2834 &oldpredlock->tag,
2836 oldtargettaghash),
2837 HASH_REMOVE, &found);
2838 Assert(found);
2839 }
2840
2841 newpredlock = (PREDICATELOCK *)
2843 &newpredlocktag,
2845 newtargettaghash),
2847 &found);
2848 if (!newpredlock)
2849 {
2850 /* Out of shared memory. Undo what we've done so far. */
2851 LWLockRelease(SerializableXactHashLock);
2852 DeleteLockTarget(newtarget, newtargettaghash);
2853 outOfShmem = true;
2854 goto exit;
2855 }
2856 if (!found)
2857 {
2858 dlist_push_tail(&(newtarget->predicateLocks),
2859 &(newpredlock->targetLink));
2860 dlist_push_tail(&(newpredlocktag.myXact->predicateLocks),
2861 &(newpredlock->xactLink));
2862 newpredlock->commitSeqNo = oldCommitSeqNo;
2863 }
2864 else
2865 {
2866 if (newpredlock->commitSeqNo < oldCommitSeqNo)
2867 newpredlock->commitSeqNo = oldCommitSeqNo;
2868 }
2869
2870 Assert(newpredlock->commitSeqNo != 0);
2871 Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
2872 || (newpredlock->tag.myXact == OldCommittedSxact));
2873 }
2874 LWLockRelease(SerializableXactHashLock);
2875
2876 if (removeOld)
2877 {
2878 Assert(dlist_is_empty(&oldtarget->predicateLocks));
2879 RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2880 }
2881 }
2882
2883
2884exit:
2885 /* Release partition locks in reverse order of acquisition. */
2886 if (oldpartitionLock < newpartitionLock)
2887 {
2888 LWLockRelease(newpartitionLock);
2889 LWLockRelease(oldpartitionLock);
2890 }
2891 else if (oldpartitionLock > newpartitionLock)
2892 {
2893 LWLockRelease(oldpartitionLock);
2894 LWLockRelease(newpartitionLock);
2895 }
2896 else
2897 LWLockRelease(newpartitionLock);
2898
2899 if (removeOld)
2900 {
2901 /* We shouldn't run out of memory if we're moving locks */
2902 Assert(!outOfShmem);
2903
2904 /* Put the scratch entry back */
2905 RestoreScratchTarget(false);
2906 }
2907
2908 return !outOfShmem;
2909}
static void DeleteLockTarget(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2667

References Assert(), PREDICATELOCK::commitSeqNo, dlist_mutable_iter::cur, DeleteLockTarget(), dlist_container, dlist_delete(), dlist_foreach_modify, dlist_init(), dlist_is_empty(), dlist_push_tail(), HASH_ENTER_NULL, HASH_FIND, HASH_REMOVE, hash_search_with_hash_value(), InvalidSerCommitSeqNo, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockHeldByMeInMode(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, OldCommittedSxact, PredicateLockHash, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetHash, PredicateLockTargetTagHashCode, RemoveScratchTarget(), RemoveTargetIfNoLongerUsed(), RestoreScratchTarget(), PREDICATELOCK::tag, PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by PredicateLockPageSplit().

◆ XidIsConcurrent()

static bool XidIsConcurrent ( TransactionId  xid)
static

Definition at line 3970 of file predicate.c.

3971{
3972 Snapshot snap;
3973
3976
3977 snap = GetTransactionSnapshot();
3978
3979 if (TransactionIdPrecedes(xid, snap->xmin))
3980 return false;
3981
3982 if (TransactionIdFollowsOrEquals(xid, snap->xmax))
3983 return true;
3984
3985 return pg_lfind32(xid, snap->xip, snap->xcnt);
3986}
static bool pg_lfind32(uint32 key, const uint32 *base, uint32 nelem)
Definition: pg_lfind.h:153
uint32 xcnt
Definition: snapshot.h:165
TransactionId xmax
Definition: snapshot.h:154
TransactionId * xip
Definition: snapshot.h:164
static bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.h:312

References Assert(), GetTopTransactionIdIfAny(), GetTransactionSnapshot(), pg_lfind32(), TransactionIdEquals, TransactionIdFollowsOrEquals(), TransactionIdIsValid, TransactionIdPrecedes(), SnapshotData::xcnt, SnapshotData::xip, SnapshotData::xmax, and SnapshotData::xmin.

Referenced by CheckForSerializableConflictOut().

Variable Documentation

◆ FinishedSerializableTransactions

dlist_head* FinishedSerializableTransactions
static

◆ LocalPredicateLockHash

◆ max_predicate_locks_per_page

int max_predicate_locks_per_page

Definition at line 373 of file predicate.c.

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_relation

int max_predicate_locks_per_relation

Definition at line 372 of file predicate.c.

Referenced by MaxPredicateChildLocks().

◆ max_predicate_locks_per_xact

int max_predicate_locks_per_xact

Definition at line 371 of file predicate.c.

Referenced by CreateLocalPredicateLockHash(), and MaxPredicateChildLocks().

◆ MySerializableXact

◆ MyXactDidWrite

◆ OldCommittedSxact

◆ PredicateLockHash

◆ PredicateLockTargetHash

◆ PredXact

◆ RWConflictPool

RWConflictPoolHeader RWConflictPool
static

◆ SavedSerializableXact

SERIALIZABLEXACT* SavedSerializableXact = InvalidSerializableXact
static

Definition at line 431 of file predicate.c.

Referenced by ReleasePredicateLocks().

◆ ScratchPartitionLock

LWLock* ScratchPartitionLock
static

Definition at line 408 of file predicate.c.

Referenced by PredicateLockShmemInit(), RemoveScratchTarget(), and RestoreScratchTarget().

◆ ScratchTargetTag

const PREDICATELOCKTARGETTAG ScratchTargetTag = {0, 0, 0, 0}
static

Definition at line 406 of file predicate.c.

Referenced by PredicateLockShmemInit(), RemoveScratchTarget(), and RestoreScratchTarget().

◆ ScratchTargetTagHash

uint32 ScratchTargetTagHash
static

Definition at line 407 of file predicate.c.

Referenced by PredicateLockShmemInit(), RemoveScratchTarget(), and RestoreScratchTarget().

◆ serialControl

◆ SerializableXidHash

◆ SerialSlruCtlData

SlruCtlData SerialSlruCtlData
static

Definition at line 324 of file predicate.c.