PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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, ItemPointer 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, ItemPointer tid, BlockNumber blkno)
 
void CheckTableForSerializableConflictIn (Relation relation)
 
void PreCommit_CheckForSerializationFailure (void)
 
void AtPrepare_PredicateLocks (void)
 
void PostPrepare_PredicateLocks (TransactionId xid)
 
void PredicateLockTwoPhaseFinish (TransactionId xid, bool isCommit)
 
void predicatelock_twophase_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
SerializableXactHandle ShareSerializableXact (void)
 
void AttachSerializableXact (SerializableXactHandle handle)
 

Variables

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:502
#define LOG2_NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:100
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327

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:202
#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET
Definition: lwlock.h:107
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 4790 of file predicate.c.

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

References Assert(), dlist_iter::cur, TwoPhasePredicateRecord::data, dlist_container, dlist_foreach, SERIALIZABLEXACT::flags, TwoPhasePredicateXactRecord::flags, InvalidSerializableXact, IsParallelWorker, TwoPhasePredicateRecord::lockRecord, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myTarget, ParallelContextActive(), SERIALIZABLEXACT::predicateLocks, RegisterTwoPhaseRecord(), PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, TwoPhasePredicateLockRecord::target, TWOPHASE_RM_PREDICATELOCK_ID, TWOPHASEPREDICATERECORD_LOCK, TWOPHASEPREDICATERECORD_XACT, TwoPhasePredicateRecord::type, TwoPhasePredicateRecord::xactRecord, SERIALIZABLEXACT::xmin, and TwoPhasePredicateXactRecord::xmin.

Referenced by PrepareTransaction().

◆ AttachSerializableXact()

void AttachSerializableXact ( SerializableXactHandle  handle)

Definition at line 5055 of file predicate.c.

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

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

Referenced by ParallelWorkerMain().

◆ 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:354

References check_slru_buffers(), and newval.

◆ CheckAndPromotePredicateLockRequest()

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2326 of file predicate.c.

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

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

Referenced by PredicateLockAcquire().

◆ CheckForSerializableConflictIn()

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

Definition at line 4336 of file predicate.c.

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

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

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

◆ CheckForSerializableConflictOut()

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

Definition at line 4023 of file predicate.c.

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

References Assert(), dlist_is_empty(), SERIALIZABLEXACT::earliestOutConflictCommit, ereport, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errdetail_internal(), errhint(), errmsg(), ERROR, FlagRWConflict(), SERIALIZABLEXACT::flags, GetTopTransactionIdIfAny(), HASH_FIND, hash_search(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXID::myXact, RWConflictExists(), SERIALIZABLEXACT::SeqNo, SerialGetMinConflictCommitSeqNo(), SerializableXidHash, SerializationNeededForRead(), SXACT_FLAG_DOOMED, SXACT_FLAG_SUMMARY_CONFLICT_OUT, SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, SERIALIZABLEXACT::topXid, TransactionIdEquals, TransactionIdIsValid, SERIALIZABLEXIDTAG::xid, and XidIsConcurrent().

Referenced by HeapCheckForSerializableConflictOut().

◆ CheckForSerializableConflictOutNeeded()

bool CheckForSerializableConflictOutNeeded ( Relation  relation,
Snapshot  snapshot 
)

Definition at line 3991 of file predicate.c.

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

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

Referenced by heap_prepare_pagescan(), and HeapCheckForSerializableConflictOut().

◆ CheckPointPredicate()

void CheckPointPredicate ( void  )

Definition at line 1041 of file predicate.c.

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

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

Referenced by CheckPointGuts().

◆ CheckTableForSerializableConflictIn()

void CheckTableForSerializableConflictIn ( Relation  relation)

Definition at line 4419 of file predicate.c.

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

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

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

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

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

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

References GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

◆ CreateLocalPredicateLockHash()

static void CreateLocalPredicateLockHash ( void  )
static

Definition at line 1940 of file predicate.c.

1941{
1942 HASHCTL hash_ctl;
1943
1944 /* Initialize the backend-local hash table of parent locks */
1946 hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1947 hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1948 LocalPredicateLockHash = hash_create("Local predicate lock",
1950 &hash_ctl,
1952}
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#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 2453 of file predicate.c.

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

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

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

2215{
2216 SERIALIZABLEXACT *sxact;
2217 PREDICATELOCK *predlock;
2218 dlist_mutable_iter iter;
2219
2220 LWLockAcquire(SerializablePredicateListLock, LW_SHARED);
2221 sxact = MySerializableXact;
2222 if (IsInParallelMode())
2224
2226 {
2227 PREDICATELOCKTAG oldlocktag;
2228 PREDICATELOCKTARGET *oldtarget;
2229 PREDICATELOCKTARGETTAG oldtargettag;
2230
2231 predlock = dlist_container(PREDICATELOCK, xactLink, iter.cur);
2232
2233 oldlocktag = predlock->tag;
2234 Assert(oldlocktag.myXact == sxact);
2235 oldtarget = oldlocktag.myTarget;
2236 oldtargettag = oldtarget->tag;
2237
2238 if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
2239 {
2240 uint32 oldtargettaghash;
2241 LWLock *partitionLock;
2243
2244 oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2245 partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2246
2247 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2248
2249 dlist_delete(&predlock->xactLink);
2250 dlist_delete(&predlock->targetLink);
2251 rmpredlock = hash_search_with_hash_value
2253 &oldlocktag,
2255 oldtargettaghash),
2256 HASH_REMOVE, NULL);
2257 Assert(rmpredlock == predlock);
2258
2259 RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2260
2261 LWLockRelease(partitionLock);
2262
2263 DecrementParentLocks(&oldtargettag);
2264 }
2265 }
2266 if (IsInParallelMode())
2268 LWLockRelease(SerializablePredicateListLock);
2269}
#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 2669 of file predicate.c.

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

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

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

4502{
4503 Assert(reader != writer);
4504
4505 /* First, see if this conflict causes failure. */
4507
4508 /* Actually do the conflict flagging. */
4509 if (reader == OldCommittedSxact)
4511 else if (writer == OldCommittedSxact)
4513 else
4514 SetRWConflict(reader, writer);
4515}
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:643
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4536
#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 2072 of file predicate.c.

2074{
2075 switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2076 {
2078 /* relation locks have no parent lock */
2079 return false;
2080
2081 case PREDLOCKTAG_PAGE:
2082 /* parent lock is relation lock */
2086
2087 return true;
2088
2089 case PREDLOCKTAG_TUPLE:
2090 /* parent lock is page lock */
2095 return true;
2096 }
2097
2098 /* not reachable */
2099 Assert(false);
2100 return false;
2101}
@ 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 = (PREDICATELOCKTARGETTAG *)
1468 palloc(sizeof(PREDICATELOCKTARGETTAG) * els);
1469 data->xacts = (SERIALIZABLEXACT *)
1470 palloc(sizeof(SERIALIZABLEXACT) * els);
1471
1472
1473 /* Scan through PredicateLockHash and copy contents */
1475
1476 el = 0;
1477
1478 while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
1479 {
1480 data->locktags[el] = predlock->tag.myTarget->tag;
1481 data->xacts[el] = *predlock->tag.myXact;
1482 el++;
1483 }
1484
1485 Assert(el == els);
1486
1487 /* Release locks in reverse order */
1488 LWLockRelease(SerializableXactHashLock);
1489 for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1491
1492 return data;
1493}
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1341
void * palloc(Size size)
Definition: mcxt.c:1939
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(), PredicateLockHash, PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::tag, and PREDICATELOCK::tag.

Referenced by pg_lock_status().

◆ GetSafeSnapshot()

static Snapshot GetSafeSnapshot ( Snapshot  origSnapshot)
static

Definition at line 1558 of file predicate.c.

1559{
1560 Snapshot snapshot;
1561
1563
1564 while (true)
1565 {
1566 /*
1567 * GetSerializableTransactionSnapshotInt is going to call
1568 * GetSnapshotData, so we need to provide it the static snapshot area
1569 * our caller passed to us. The pointer returned is actually the same
1570 * one passed to it, but we avoid assuming that here.
1571 */
1572 snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
1573 NULL, InvalidPid);
1574
1576 return snapshot; /* no concurrent r/w xacts; it's safe */
1577
1578 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1579
1580 /*
1581 * Wait for concurrent transactions to finish. Stop early if one of
1582 * them marked us as conflicted.
1583 */
1587 {
1588 LWLockRelease(SerializableXactHashLock);
1589 ProcWaitForSignal(WAIT_EVENT_SAFE_SNAPSHOT);
1590 LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1591 }
1592 MySerializableXact->flags &= ~SXACT_FLAG_DEFERRABLE_WAITING;
1593
1595 {
1596 LWLockRelease(SerializableXactHashLock);
1597 break; /* success */
1598 }
1599
1600 LWLockRelease(SerializableXactHashLock);
1601
1602 /* else, need to retry... */
1605 errmsg_internal("deferrable snapshot was unsafe; trying a new one")));
1606 ReleasePredicateLocks(false, false);
1607 }
1608
1609 /*
1610 * Now we have a safe snapshot, so we don't need to do any further checks.
1611 */
1613 ReleasePredicateLocks(false, true);
1614
1615 return snapshot;
1616}
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1158
#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:1764
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3312
#define SXACT_FLAG_DEFERRABLE_WAITING
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1975
bool XactDeferrable
Definition: xact.c:85
bool XactReadOnly
Definition: xact.c:82

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

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

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

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

Referenced by GetTransactionSnapshot().

◆ GetSerializableTransactionSnapshotInt()

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

Definition at line 1764 of file predicate.c.

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

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

2290{
2291 switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
2292 {
2298
2299 case PREDLOCKTAG_PAGE:
2301
2302 case PREDLOCKTAG_TUPLE:
2303
2304 /*
2305 * not reachable: nothing is finer-granularity than a tuple, so we
2306 * should never try to promote to it.
2307 */
2308 Assert(false);
2309 return 0;
2310 }
2311
2312 /* not reachable */
2313 Assert(false);
2314 return 0;
2315}
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 4536 of file predicate.c.

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

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

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

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

◆ PostPrepare_PredicateLocks()

◆ PreCommit_CheckForSerializationFailure()

void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4703 of file predicate.c.

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

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 ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 4909 of file predicate.c.

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

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

◆ PredicateLockAcquire()

static void PredicateLockAcquire ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2517 of file predicate.c.

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

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

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

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:648
#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 3229 of file predicate.c.

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

References PredicateLockPageSplit().

Referenced by _bt_mark_page_halfdead(), and ginDeletePage().

◆ PredicateLockPageSplit()

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

Definition at line 3144 of file predicate.c.

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

References Assert(), BlockNumberIsValid(), RelFileLocator::dbOid, GetParentPredicateLockTag(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PredicateLockingNeededForRelation(), PredXact, RelationData::rd_id, RelationData::rd_locator, SET_PREDICATELOCKTARGETTAG_PAGE, success, PredXactListData::SxactGlobalXmin, TransactionIdIsValid, and TransferPredicateLocksToNewTarget().

Referenced by _bt_insertonpg(), _hash_splitbucket(), createPostingTree(), ginPlaceToPage(), gistplacetopage(), and PredicateLockPageCombine().

◆ PredicateLockRelation()

void PredicateLockRelation ( Relation  relation,
Snapshot  snapshot 
)

◆ PredicateLockShmemInit()

void PredicateLockShmemInit ( void  )

Definition at line 1145 of file predicate.c.

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

Referenced by CreateOrAttachShmemStructs().

◆ PredicateLockShmemSize()

Size PredicateLockShmemSize ( void  )

Definition at line 1357 of file predicate.c.

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

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

Referenced by CalculateShmemSize().

◆ PredicateLockTID()

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

Definition at line 2621 of file predicate.c.

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

References RelFileLocator::dbOid, ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), PredicateLockAcquire(), PredicateLockExists(), RelationData::rd_id, RelationData::rd_index, RelationData::rd_locator, SerializationNeededForRead(), SET_PREDICATELOCKTARGETTAG_RELATION, SET_PREDICATELOCKTARGETTAG_TUPLE, and TransactionIdIsCurrentTransactionId().

Referenced by BitmapHeapScanNextBlock(), heap_fetch(), and heap_hot_search_buffer().

◆ PredicateLockTwoPhaseFinish()

void PredicateLockTwoPhaseFinish ( TransactionId  xid,
bool  isCommit 
)

Definition at line 4882 of file predicate.c.

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

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

Referenced by FinishPreparedTransaction().

◆ RegisterPredicateLockingXid()

void RegisterPredicateLockingXid ( TransactionId  xid)

Definition at line 1959 of file predicate.c.

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

References Assert(), HASH_ENTER, hash_search(), InvalidSerializableXact, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MySerializableXact, SERIALIZABLEXID::myXact, SerializableXidHash, SERIALIZABLEXACT::topXid, TransactionIdIsValid, and SERIALIZABLEXIDTAG::xid.

Referenced by AssignTransactionId().

◆ ReleaseOneSerializableXact()

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

Definition at line 3835 of file predicate.c.

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

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

3680{
3682 MyXactDidWrite = false;
3683
3684 /* Delete per-transaction lock table */
3685 if (LocalPredicateLockHash != NULL)
3686 {
3689 }
3690}

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

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

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}
uint32 TransactionId
Definition: c.h:623
#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:501
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:374
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:175
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:604

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",
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}
@ LWTRANCHE_SERIAL_SLRU
Definition: lwlock.h:219
@ LWTRANCHE_SERIAL_BUFFER
Definition: lwlock.h:189
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:251
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:199
@ SYNC_HANDLER_NONE
Definition: sync.h:42

References Assert(), SerialControlData::headPage, SerialControlData::headXid, InvalidTransactionId, IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), LWTRANCHE_SERIAL_BUFFER, LWTRANCHE_SERIAL_SLRU, 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 1722 of file predicate.c.

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

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

Referenced by SetTransactionSnapshot().

◆ ShareSerializableXact()

SerializableXactHandle ShareSerializableXact ( void  )

Definition at line 5046 of file predicate.c.

5047{
5048 return MySerializableXact;
5049}

References MySerializableXact.

Referenced by InitializeParallelDSM().

◆ SummarizeOldestCommittedSxact()

static void SummarizeOldestCommittedSxact ( void  )
static

Definition at line 1503 of file predicate.c.

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

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

References DropAllPredicateLocksFromTable().

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

◆ TransferPredicateLocksToNewTarget()

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

Definition at line 2730 of file predicate.c.

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

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

3973{
3974 Snapshot snap;
3975
3978
3979 snap = GetTransactionSnapshot();
3980
3981 if (TransactionIdPrecedes(xid, snap->xmin))
3982 return false;
3983
3984 if (TransactionIdFollowsOrEquals(xid, snap->xmax))
3985 return true;
3986
3987 return pg_lfind32(xid, snap->xip, snap->xcnt);
3988}
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
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:329

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.