PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
predicate.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/slru.h"
#include "access/subtrans.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 "storage/bufmgr.h"
#include "storage/predicate.h"
#include "storage/predicate_internals.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/tqual.h"
Include dependency graph for predicate.c:

Go to the source code of this file.

Data Structures

struct  OldSerXidControlData
 

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)   (!SHMQueueIsDetached(&((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 PredicateLockTargetTagHashCode(predicatelocktargettag)   get_hash_value(PredicateLockTargetHash, predicatelocktargettag)
 
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
 
#define OldSerXidSlruCtl   (&OldSerXidSlruCtlData)
 
#define OLDSERXID_PAGESIZE   BLCKSZ
 
#define OLDSERXID_ENTRYSIZE   sizeof(SerCommitSeqNo)
 
#define OLDSERXID_ENTRIESPERPAGE   (OLDSERXID_PAGESIZE / OLDSERXID_ENTRYSIZE)
 
#define OLDSERXID_MAX_PAGE
 
#define OldSerXidNextPage(page)   (((page) >= OLDSERXID_MAX_PAGE) ? 0 : (page) + 1)
 
#define OldSerXidValue(slotno, xid)
 
#define OldSerXidPage(xid)   ((((uint32) (xid)) / OLDSERXID_ENTRIESPERPAGE) % (OLDSERXID_MAX_PAGE + 1))
 
#define OldSerXidSegment(page)   ((page) / SLRU_PAGES_PER_SEGMENT)
 

Typedefs

typedef struct OldSerXidControlData OldSerXidControlData
 
typedef struct
OldSerXidControlData
OldSerXidControl
 

Functions

static SERIALIZABLEXACTCreatePredXact (void)
 
static void ReleasePredXact (SERIALIZABLEXACT *sxact)
 
static SERIALIZABLEXACTFirstPredXact (void)
 
static SERIALIZABLEXACTNextPredXact (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 OldSerXidPagePrecedesLogically (int p, int q)
 
static void OldSerXidInit (void)
 
static void OldSerXidAdd (TransactionId xid, SerCommitSeqNo minConflictCommitSeqNo)
 
static SerCommitSeqNo OldSerXidGetMinConflictCommitSeqNo (TransactionId xid)
 
static void OldSerXidSetActiveSerXmin (TransactionId xid)
 
static uint32 predicatelock_hash (const void *key, Size keysize)
 
static void SummarizeOldestCommittedSxact (void)
 
static Snapshot GetSafeSnapshot (Snapshot snapshot)
 
static Snapshot GetSerializableTransactionSnapshotInt (Snapshot snapshot, TransactionId sourcexid)
 
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 PredicateLockPromotionThreshold (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 bool PredicateLockingNeededForRelation (Relation relation)
 
static bool SerializationNeededForRead (Relation relation, Snapshot snapshot)
 
static bool SerializationNeededForWrite (Relation relation)
 
void CheckPointPredicate (void)
 
void InitPredicateLocks (void)
 
Size PredicateLockShmemSize (void)
 
PredicateLockDataGetPredicateLockStatusData (void)
 
Snapshot GetSerializableTransactionSnapshot (Snapshot snapshot)
 
void SetSerializableTransactionSnapshot (Snapshot snapshot, TransactionId sourcexid)
 
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 PredicateLockTuple (Relation relation, HeapTuple tuple, Snapshot snapshot)
 
void TransferPredicateLocksToHeapRelation (Relation relation)
 
void PredicateLockPageSplit (Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
 
void PredicateLockPageCombine (Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
 
void ReleasePredicateLocks (bool isCommit)
 
void CheckForSerializableConflictOut (bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
 
void CheckForSerializableConflictIn (Relation relation, HeapTuple tuple, Buffer buffer)
 
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)
 

Variables

static SlruCtlData OldSerXidSlruCtlData
 
static OldSerXidControl oldSerXidControl
 
static SERIALIZABLEXACTOldCommittedSxact
 
int max_predicate_locks_per_xact
 
static PredXactList PredXact
 
static RWConflictPoolHeader RWConflictPool
 
static HTABSerializableXidHash
 
static HTABPredicateLockTargetHash
 
static HTABPredicateLockHash
 
static SHM_QUEUEFinishedSerializableTransactions
 
static const PREDICATELOCKTARGETTAG ScratchTargetTag = {0, 0, 0, 0}
 
static uint32 ScratchTargetTagHash
 
static LWLockScratchPartitionLock
 
static HTABLocalPredicateLockHash = NULL
 
static SERIALIZABLEXACTMySerializableXact = InvalidSerializableXact
 
static bool MyXactDidWrite = false
 

Macro Definition Documentation

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

Definition at line 251 of file predicate.c.

Referenced by InitPredicateLocks(), and PredicateLockShmemSize().

#define OLDSERXID_ENTRIESPERPAGE   (OLDSERXID_PAGESIZE / OLDSERXID_ENTRYSIZE)

Definition at line 316 of file predicate.c.

#define OLDSERXID_ENTRYSIZE   sizeof(SerCommitSeqNo)

Definition at line 315 of file predicate.c.

#define OLDSERXID_MAX_PAGE
Value:
Min(SLRU_PAGES_PER_SEGMENT * 0x10000 - 1, \
#define Min(x, y)
Definition: c.h:802
#define OLDSERXID_ENTRIESPERPAGE
Definition: predicate.c:316
#define MaxTransactionId
Definition: transam.h:35
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:37

Definition at line 322 of file predicate.c.

Referenced by OldSerXidPagePrecedesLogically().

#define OLDSERXID_PAGESIZE   BLCKSZ

Definition at line 314 of file predicate.c.

#define OldSerXidNextPage (   page)    (((page) >= OLDSERXID_MAX_PAGE) ? 0 : (page) + 1)

Definition at line 325 of file predicate.c.

Referenced by OldSerXidAdd().

#define OldSerXidPage (   xid)    ((((uint32) (xid)) / OLDSERXID_ENTRIESPERPAGE) % (OLDSERXID_MAX_PAGE + 1))
#define OldSerXidSegment (   page)    ((page) / SLRU_PAGES_PER_SEGMENT)

Definition at line 332 of file predicate.c.

#define OldSerXidSlruCtl   (&OldSerXidSlruCtlData)
#define OldSerXidValue (   slotno,
  xid 
)
Value:
(OldSerXidSlruCtl->shared->page_buffer[slotno] + \
#define OLDSERXID_ENTRYSIZE
Definition: predicate.c:315
#define OldSerXidSlruCtl
Definition: predicate.c:312
#define OLDSERXID_ENTRIESPERPAGE
Definition: predicate.c:316
unsigned int uint32
Definition: c.h:265
uint64 SerCommitSeqNo

Definition at line 327 of file predicate.c.

Referenced by OldSerXidAdd(), and OldSerXidGetMinConflictCommitSeqNo().

#define PredicateLockHashCodeFromTargetHashCode (   predicatelocktag,
  targethash 
)
#define PredicateLockHashPartition (   hashcode)    ((hashcode) % NUM_PREDICATELOCK_PARTITIONS)

Definition at line 243 of file predicate.c.

#define PredicateLockHashPartitionLock (   hashcode)
#define PredicateLockHashPartitionLockByIndex (   i)    (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
#define SxactHasConflictOut (   sxact)    (((sxact)->flags & SXACT_FLAG_CONFLICT_OUT) != 0)
#define SxactHasSummaryConflictIn (   sxact)    (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_IN) != 0)
#define SxactHasSummaryConflictOut (   sxact)    (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_OUT) != 0)
#define SxactIsDeferrableWaiting (   sxact)    (((sxact)->flags & SXACT_FLAG_DEFERRABLE_WAITING) != 0)

Definition at line 277 of file predicate.c.

Referenced by ReleasePredicateLocks().

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

Definition at line 254 of file predicate.c.

Referenced by ReleaseOneSerializableXact(), and ReleasePredicateLocks().

#define SxactIsRolledBack (   sxact)    (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0)
#define SxactIsROSafe (   sxact)    (((sxact)->flags & SXACT_FLAG_RO_SAFE) != 0)
#define SxactIsROUnsafe (   sxact)    (((sxact)->flags & SXACT_FLAG_RO_UNSAFE) != 0)

Definition at line 279 of file predicate.c.

Referenced by GetSafeSnapshot(), and ReleasePredicateLocks().

#define TargetTagIsCoveredBy (   covered_target,
  covering_target 
)
Value:
((GET_PREDICATELOCKTARGETTAG_RELATION(covered_target) == /* (2) */ \
&& (GET_PREDICATELOCKTARGETTAG_OFFSET(covering_target) == \
&& (((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) */ \
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
#define GET_PREDICATELOCKTARGETTAG_PAGE(locktag)
#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag)
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
#define InvalidOffsetNumber
Definition: off.h:26
#define InvalidBlockNumber
Definition: block.h:33

Definition at line 220 of file predicate.c.

Referenced by DeleteChildTargetLocks().

Typedef Documentation

Definition at line 342 of file predicate.c.

Function Documentation

void AtPrepare_PredicateLocks ( void  )

Definition at line 4722 of file predicate.c.

References TwoPhasePredicateRecord::data, SERIALIZABLEXACT::flags, TwoPhasePredicateXactRecord::flags, InvalidSerializableXact, TwoPhasePredicateRecord::lockRecord, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myTarget, NULL, offsetof, SERIALIZABLEXACT::predicateLocks, RegisterTwoPhaseRecord(), SHMQueueNext(), PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, TwoPhasePredicateLockRecord::target, TWOPHASE_RM_PREDICATELOCK_ID, TWOPHASEPREDICATERECORD_LOCK, TWOPHASEPREDICATERECORD_XACT, TwoPhasePredicateRecord::type, PREDICATELOCK::xactLink, TwoPhasePredicateRecord::xactRecord, SERIALIZABLEXACT::xmin, and TwoPhasePredicateXactRecord::xmin.

Referenced by PrepareTransaction().

4723 {
4724  PREDICATELOCK *predlock;
4725  SERIALIZABLEXACT *sxact;
4726  TwoPhasePredicateRecord record;
4727  TwoPhasePredicateXactRecord *xactRecord;
4728  TwoPhasePredicateLockRecord *lockRecord;
4729 
4730  sxact = MySerializableXact;
4731  xactRecord = &(record.data.xactRecord);
4732  lockRecord = &(record.data.lockRecord);
4733 
4735  return;
4736 
4737  /* Generate an xact record for our SERIALIZABLEXACT */
4739  xactRecord->xmin = MySerializableXact->xmin;
4740  xactRecord->flags = MySerializableXact->flags;
4741 
4742  /*
4743  * Note that we don't include the list of conflicts in our out in the
4744  * statefile, because new conflicts can be added even after the
4745  * transaction prepares. We'll just make a conservative assumption during
4746  * recovery instead.
4747  */
4748 
4750  &record, sizeof(record));
4751 
4752  /*
4753  * Generate a lock record for each lock.
4754  *
4755  * To do this, we need to walk the predicate lock list in our sxact rather
4756  * than using the local predicate lock table because the latter is not
4757  * guaranteed to be accurate.
4758  */
4759  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
4760 
4761  predlock = (PREDICATELOCK *)
4762  SHMQueueNext(&(sxact->predicateLocks),
4763  &(sxact->predicateLocks),
4764  offsetof(PREDICATELOCK, xactLink));
4765 
4766  while (predlock != NULL)
4767  {
4769  lockRecord->target = predlock->tag.myTarget->tag;
4770 
4772  &record, sizeof(record));
4773 
4774  predlock = (PREDICATELOCK *)
4775  SHMQueueNext(&(sxact->predicateLocks),
4776  &(predlock->xactLink),
4777  offsetof(PREDICATELOCK, xactLink));
4778  }
4779 
4780  LWLockRelease(SerializablePredicateLockListLock);
4781 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:404
TwoPhasePredicateRecordType type
union TwoPhasePredicateRecord::@57 data
PREDICATELOCKTARGETTAG target
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1120
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define TWOPHASE_RM_PREDICATELOCK_ID
Definition: twophase_rmgr.h:28
TwoPhasePredicateXactRecord xactRecord
#define InvalidSerializableXact
PREDICATELOCKTAG tag
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
#define NULL
Definition: c.h:226
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
TwoPhasePredicateLockRecord lockRecord
#define offsetof(type, field)
Definition: c.h:551
PREDICATELOCKTARGET * myTarget
static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag)
static

Definition at line 2168 of file predicate.c.

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

Referenced by PredicateLockAcquire().

2169 {
2170  PREDICATELOCKTARGETTAG targettag,
2171  nexttag,
2172  promotiontag;
2173  LOCALPREDICATELOCK *parentlock;
2174  bool found,
2175  promote;
2176 
2177  promote = false;
2178 
2179  targettag = *reqtag;
2180 
2181  /* check parents iteratively */
2182  while (GetParentPredicateLockTag(&targettag, &nexttag))
2183  {
2184  targettag = nexttag;
2186  &targettag,
2187  HASH_ENTER,
2188  &found);
2189  if (!found)
2190  {
2191  parentlock->held = false;
2192  parentlock->childLocks = 1;
2193  }
2194  else
2195  parentlock->childLocks++;
2196 
2197  if (parentlock->childLocks >=
2198  PredicateLockPromotionThreshold(&targettag))
2199  {
2200  /*
2201  * We should promote to this parent lock. Continue to check its
2202  * ancestors, however, both to get their child counts right and to
2203  * check whether we should just go ahead and promote to one of
2204  * them.
2205  */
2206  promotiontag = targettag;
2207  promote = true;
2208  }
2209  }
2210 
2211  if (promote)
2212  {
2213  /* acquire coarsest ancestor eligible for promotion */
2214  PredicateLockAcquire(&promotiontag);
2215  return true;
2216  }
2217  else
2218  return false;
2219 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
static int PredicateLockPromotionThreshold(const PREDICATELOCKTARGETTAG *tag)
Definition: predicate.c:2134
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2356
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:1917
static HTAB * LocalPredicateLockHash
Definition: predicate.c:397
void CheckForSerializableConflictIn ( Relation  relation,
HeapTuple  tuple,
Buffer  buffer 
)

Definition at line 4243 of file predicate.c.

References BufferGetBlockNumber(), BufferIsValid, CheckTargetForConflictsIn(), RelFileNode::dbNode, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, MyXactDidWrite, NULL, RelationData::rd_id, RelationData::rd_node, SerializationNeededForWrite(), SET_PREDICATELOCKTARGETTAG_PAGE, SET_PREDICATELOCKTARGETTAG_RELATION, SET_PREDICATELOCKTARGETTAG_TUPLE, SxactIsDoomed, and HeapTupleData::t_self.

Referenced by _bt_check_unique(), _bt_doinsert(), heap_delete(), heap_insert(), heap_multi_insert(), heap_update(), and index_insert().

4245 {
4246  PREDICATELOCKTARGETTAG targettag;
4247 
4248  if (!SerializationNeededForWrite(relation))
4249  return;
4250 
4251  /* Check if someone else has already decided that we need to die */
4253  ereport(ERROR,
4254  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4255  errmsg("could not serialize access due to read/write dependencies among transactions"),
4256  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
4257  errhint("The transaction might succeed if retried.")));
4258 
4259  /*
4260  * We're doing a write which might cause rw-conflicts now or later.
4261  * Memorize that fact.
4262  */
4263  MyXactDidWrite = true;
4264 
4265  /*
4266  * It is important that we check for locks from the finest granularity to
4267  * the coarsest granularity, so that granularity promotion doesn't cause
4268  * us to miss a lock. The new (coarser) lock will be acquired before the
4269  * old (finer) locks are released.
4270  *
4271  * It is not possible to take and hold a lock across the checks for all
4272  * granularities because each target could be in a separate partition.
4273  */
4274  if (tuple != NULL)
4275  {
4277  relation->rd_node.dbNode,
4278  relation->rd_id,
4279  ItemPointerGetBlockNumber(&(tuple->t_self)),
4280  ItemPointerGetOffsetNumber(&(tuple->t_self)));
4281  CheckTargetForConflictsIn(&targettag);
4282  }
4283 
4284  if (BufferIsValid(buffer))
4285  {
4287  relation->rd_node.dbNode,
4288  relation->rd_id,
4289  BufferGetBlockNumber(buffer));
4290  CheckTargetForConflictsIn(&targettag);
4291  }
4292 
4294  relation->rd_node.dbNode,
4295  relation->rd_id);
4296  CheckTargetForConflictsIn(&targettag);
4297 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:404
int errhint(const char *fmt,...)
Definition: elog.c:987
static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:4065
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
int errcode(int sqlerrcode)
Definition: elog.c:575
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:534
#define SET_PREDICATELOCKTARGETTAG_TUPLE(locktag, dboid, reloid, blocknum, offnum)
#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag, dboid, reloid)
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
#define SxactIsDoomed(sxact)
Definition: predicate.c:267
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define ereport(elevel, rest)
Definition: elog.h:122
Oid rd_id
Definition: rel.h:115
RelFileNode rd_node
Definition: rel.h:85
#define NULL
Definition: c.h:226
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:76
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2588
int errmsg(const char *fmt,...)
Definition: elog.c:797
static bool MyXactDidWrite
Definition: predicate.c:405
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:66
void CheckForSerializableConflictOut ( bool  visible,
Relation  relation,
HeapTuple  tuple,
Buffer  buffer,
Snapshot  snapshot 
)

Definition at line 3862 of file predicate.c.

References Assert, SERIALIZABLEXACT::earliestOutConflictCommit, elog, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, FlagRWConflict(), SERIALIZABLEXACT::flags, GetTopTransactionIdIfAny(), HASH_FIND, hash_search(), HEAPTUPLE_DEAD, HEAPTUPLE_DELETE_IN_PROGRESS, HEAPTUPLE_INSERT_IN_PROGRESS, HEAPTUPLE_LIVE, HEAPTUPLE_RECENTLY_DEAD, HeapTupleHeaderGetUpdateXid, HeapTupleHeaderGetXmin, HeapTupleSatisfiesVacuum(), SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, InvalidTransactionId, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SERIALIZABLEXID::myXact, NULL, OldSerXidGetMinConflictCommitSeqNo(), RWConflictExists(), SERIALIZABLEXACT::SeqNo, SerializationNeededForRead(), SHMQueueEmpty(), SubTransGetTopmostTransaction(), SXACT_FLAG_DOOMED, SXACT_FLAG_SUMMARY_CONFLICT_OUT, SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, HeapTupleData::t_data, SERIALIZABLEXACT::topXid, TransactionIdEquals, TransactionIdFollowsOrEquals(), TransactionIdIsValid, TransactionIdPrecedes(), TransactionXmin, SERIALIZABLEXIDTAG::xid, and XidIsConcurrent().

Referenced by bitgetpage(), heap_fetch(), heap_get_latest_tid(), heap_hot_search_buffer(), heapgetpage(), heapgettup(), and tablesample_getnext().

3865 {
3866  TransactionId xid;
3867  SERIALIZABLEXIDTAG sxidtag;
3868  SERIALIZABLEXID *sxid;
3869  SERIALIZABLEXACT *sxact;
3870  HTSV_Result htsvResult;
3871 
3872  if (!SerializationNeededForRead(relation, snapshot))
3873  return;
3874 
3875  /* Check if someone else has already decided that we need to die */
3877  {
3878  ereport(ERROR,
3879  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
3880  errmsg("could not serialize access due to read/write dependencies among transactions"),
3881  errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
3882  errhint("The transaction might succeed if retried.")));
3883  }
3884 
3885  /*
3886  * Check to see whether the tuple has been written to by a concurrent
3887  * transaction, either to create it not visible to us, or to delete it
3888  * while it is visible to us. The "visible" bool indicates whether the
3889  * tuple is visible to us, while HeapTupleSatisfiesVacuum checks what else
3890  * is going on with it.
3891  */
3892  htsvResult = HeapTupleSatisfiesVacuum(tuple, TransactionXmin, buffer);
3893  switch (htsvResult)
3894  {
3895  case HEAPTUPLE_LIVE:
3896  if (visible)
3897  return;
3898  xid = HeapTupleHeaderGetXmin(tuple->t_data);
3899  break;
3901  if (!visible)
3902  return;
3903  xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
3904  break;
3906  xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
3907  break;
3909  xid = HeapTupleHeaderGetXmin(tuple->t_data);
3910  break;
3911  case HEAPTUPLE_DEAD:
3912  return;
3913  default:
3914 
3915  /*
3916  * The only way to get to this default clause is if a new value is
3917  * added to the enum type without adding it to this switch
3918  * statement. That's a bug, so elog.
3919  */
3920  elog(ERROR, "unrecognized return value from HeapTupleSatisfiesVacuum: %u", htsvResult);
3921 
3922  /*
3923  * In spite of having all enum values covered and calling elog on
3924  * this default, some compilers think this is a code path which
3925  * allows xid to be used below without initialization. Silence
3926  * that warning.
3927  */
3928  xid = InvalidTransactionId;
3929  }
3932 
3933  /*
3934  * Find top level xid. Bail out if xid is too early to be a conflict, or
3935  * if it's our own xid.
3936  */
3938  return;
3939  xid = SubTransGetTopmostTransaction(xid);
3941  return;
3943  return;
3944 
3945  /*
3946  * Find sxact or summarized info for the top level xid.
3947  */
3948  sxidtag.xid = xid;
3949  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3950  sxid = (SERIALIZABLEXID *)
3952  if (!sxid)
3953  {
3954  /*
3955  * Transaction not found in "normal" SSI structures. Check whether it
3956  * got pushed out to SLRU storage for "old committed" transactions.
3957  */
3958  SerCommitSeqNo conflictCommitSeqNo;
3959 
3960  conflictCommitSeqNo = OldSerXidGetMinConflictCommitSeqNo(xid);
3961  if (conflictCommitSeqNo != 0)
3962  {
3963  if (conflictCommitSeqNo != InvalidSerCommitSeqNo
3965  || conflictCommitSeqNo
3967  ereport(ERROR,
3968  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
3969  errmsg("could not serialize access due to read/write dependencies among transactions"),
3970  errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
3971  errhint("The transaction might succeed if retried.")));
3972 
3975  ereport(ERROR,
3976  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
3977  errmsg("could not serialize access due to read/write dependencies among transactions"),
3978  errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
3979  errhint("The transaction might succeed if retried.")));
3980 
3982  }
3983 
3984  /* It's not serializable or otherwise not important. */
3985  LWLockRelease(SerializableXactHashLock);
3986  return;
3987  }
3988  sxact = sxid->myXact;
3989  Assert(TransactionIdEquals(sxact->topXid, xid));
3990  if (sxact == MySerializableXact || SxactIsDoomed(sxact))
3991  {
3992  /* Can't conflict with ourself or a transaction that will roll back. */
3993  LWLockRelease(SerializableXactHashLock);
3994  return;
3995  }
3996 
3997  /*
3998  * We have a conflict out to a transaction which has a conflict out to a
3999  * summarized transaction. That summarized transaction must have
4000  * committed first, and we can't tell when it committed in relation to our
4001  * snapshot acquisition, so something needs to be canceled.
4002  */
4003  if (SxactHasSummaryConflictOut(sxact))
4004  {
4005  if (!SxactIsPrepared(sxact))
4006  {
4007  sxact->flags |= SXACT_FLAG_DOOMED;
4008  LWLockRelease(SerializableXactHashLock);
4009  return;
4010  }
4011  else
4012  {
4013  LWLockRelease(SerializableXactHashLock);
4014  ereport(ERROR,
4015  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4016  errmsg("could not serialize access due to read/write dependencies among transactions"),
4017  errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
4018  errhint("The transaction might succeed if retried.")));
4019  }
4020  }
4021 
4022  /*
4023  * If this is a read-only transaction and the writing transaction has
4024  * committed, and it doesn't have a rw-conflict to a transaction which
4025  * committed before it, no conflict.
4026  */
4028  && SxactIsCommitted(sxact)
4029  && !SxactHasSummaryConflictOut(sxact)
4030  && (!SxactHasConflictOut(sxact)
4032  {
4033  /* Read-only transaction will appear to run first. No conflict. */
4034  LWLockRelease(SerializableXactHashLock);
4035  return;
4036  }
4037 
4038  if (!XidIsConcurrent(xid))
4039  {
4040  /* This write was already in our snapshot; no conflict. */
4041  LWLockRelease(SerializableXactHashLock);
4042  return;
4043  }
4044 
4046  {
4047  /* We don't want duplicate conflict records in the list. */
4048  LWLockRelease(SerializableXactHashLock);
4049  return;
4050  }
4051 
4052  /*
4053  * Flag the conflict. But first, if this conflict creates a dangerous
4054  * structure, ereport an error.
4055  */
4057  LWLockRelease(SerializableXactHashLock);
4058 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:359
#define SxactIsReadOnly(sxact)
Definition: predicate.c:268
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:404
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:629
int errhint(const char *fmt,...)
Definition: elog.c:987
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4419
uint32 TransactionId
Definition: c.h:394
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:269
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
Definition: subtrans.c:147
static bool XidIsConcurrent(TransactionId xid)
Definition: predicate.c:3819
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
Definition: tqual.c:1164
int errcode(int sqlerrcode)
Definition: elog.c:575
static HTAB * SerializableXidHash
Definition: predicate.c:379
SERIALIZABLEXACT * myXact
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
#define SxactIsPrepared(sxact)
Definition: predicate.c:265
HTSV_Result
Definition: tqual.h:49
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
TransactionId TransactionXmin
Definition: snapmgr.c:164
HeapTupleHeader t_data
Definition: htup.h:67
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define SxactIsDoomed(sxact)
Definition: predicate.c:267
#define ERROR
Definition: elog.h:43
union SERIALIZABLEXACT::@56 SeqNo
#define InvalidTransactionId
Definition: transam.h:31
SerCommitSeqNo lastCommitBeforeSnapshot
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:403
#define ereport(elevel, rest)
Definition: elog.h:122
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:270
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define InvalidSerCommitSeqNo
bool SHMQueueEmpty(const SHM_QUEUE *queue)
Definition: shmqueue.c:180
SerCommitSeqNo earliestOutConflictCommit
static SerCommitSeqNo OldSerXidGetMinConflictCommitSeqNo(TransactionId xid)
Definition: predicate.c:940
uint64 SerCommitSeqNo
#define SXACT_FLAG_DOOMED
#define SxactHasConflictOut(sxact)
Definition: predicate.c:276
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:307
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
static bool SerializationNeededForRead(Relation relation, Snapshot snapshot)
Definition: predicate.c:490
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define SxactIsCommitted(sxact)
Definition: predicate.c:264
void CheckPointPredicate ( void  )

Definition at line 1032 of file predicate.c.

References OldSerXidControlData::headPage, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), OldSerXidPage, OldSerXidSlruCtl, SimpleLruFlush(), SimpleLruTruncate(), OldSerXidControlData::tailXid, and TransactionIdIsValid.

Referenced by CheckPointGuts().

1033 {
1034  int tailPage;
1035 
1036  LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);
1037 
1038  /* Exit quickly if the SLRU is currently not in use. */
1039  if (oldSerXidControl->headPage < 0)
1040  {
1041  LWLockRelease(OldSerXidLock);
1042  return;
1043  }
1044 
1046  {
1047  /* We can truncate the SLRU up to the page containing tailXid */
1048  tailPage = OldSerXidPage(oldSerXidControl->tailXid);
1049  }
1050  else
1051  {
1052  /*
1053  * The SLRU is no longer needed. Truncate to head before we set head
1054  * invalid.
1055  *
1056  * XXX: It's possible that the SLRU is not needed again until XID
1057  * wrap-around has happened, so that the segment containing headPage
1058  * that we leave behind will appear to be new again. In that case it
1059  * won't be removed until XID horizon advances enough to make it
1060  * current again.
1061  */
1062  tailPage = oldSerXidControl->headPage;
1063  oldSerXidControl->headPage = -1;
1064  }
1065 
1066  LWLockRelease(OldSerXidLock);
1067 
1068  /* Truncate away pages that are no longer required */
1070 
1071  /*
1072  * Flush dirty SLRU pages to disk
1073  *
1074  * This is not actually necessary from a correctness point of view. We do
1075  * it merely as a debugging aid.
1076  *
1077  * We're doing this after the truncation to avoid writing pages right
1078  * before deleting the file in which they sit, which would be completely
1079  * pointless.
1080  */
1082 }
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1153
#define OldSerXidPage(xid)
Definition: predicate.c:331
#define OldSerXidSlruCtl
Definition: predicate.c:312
void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1090
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
static OldSerXidControl oldSerXidControl
Definition: predicate.c:344
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId tailXid
Definition: predicate.c:338
void CheckTableForSerializableConflictIn ( Relation  relation)

Definition at line 4327 of file predicate.c.

References Assert, RelFileNode::dbNode, FlagRWConflict(), GET_PREDICATELOCKTARGETTAG_DB, GET_PREDICATELOCKTARGETTAG_RELATION, hash_seq_init(), hash_seq_search(), i, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myXact, MyXactDidWrite, NULL, NUM_PREDICATELOCK_PARTITIONS, offsetof, PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::predicateLocks, RelationData::rd_id, RelationData::rd_index, RelationData::rd_node, RWConflictExists(), SerializationNeededForWrite(), SHMQueueNext(), PredXactListData::SxactGlobalXmin, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, and TransactionIdIsValid.

Referenced by ExecuteTruncate(), and heap_drop_with_catalog().

4328 {
4329  HASH_SEQ_STATUS seqstat;
4330  PREDICATELOCKTARGET *target;
4331  Oid dbId;
4332  Oid heapId;
4333  int i;
4334 
4335  /*
4336  * Bail out quickly if there are no serializable transactions running.
4337  * It's safe to check this without taking locks because the caller is
4338  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
4339  * would matter here can be acquired while that is held.
4340  */
4342  return;
4343 
4344  if (!SerializationNeededForWrite(relation))
4345  return;
4346 
4347  /*
4348  * We're doing a write which might cause rw-conflicts now or later.
4349  * Memorize that fact.
4350  */
4351  MyXactDidWrite = true;
4352 
4353  Assert(relation->rd_index == NULL); /* not an index relation */
4354 
4355  dbId = relation->rd_node.dbNode;
4356  heapId = relation->rd_id;
4357 
4358  LWLockAcquire(SerializablePredicateLockListLock, LW_EXCLUSIVE);
4359  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
4361  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4362 
4363  /* Scan through target list */
4365 
4366  while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
4367  {
4368  PREDICATELOCK *predlock;
4369 
4370  /*
4371  * Check whether this is a target which needs attention.
4372  */
4373  if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
4374  continue; /* wrong relation id */
4375  if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
4376  continue; /* wrong database id */
4377 
4378  /*
4379  * Loop through locks for this target and flag conflicts.
4380  */
4381  predlock = (PREDICATELOCK *)
4382  SHMQueueNext(&(target->predicateLocks),
4383  &(target->predicateLocks),
4384  offsetof(PREDICATELOCK, targetLink));
4385  while (predlock)
4386  {
4387  PREDICATELOCK *nextpredlock;
4388 
4389  nextpredlock = (PREDICATELOCK *)
4390  SHMQueueNext(&(target->predicateLocks),
4391  &(predlock->targetLink),
4392  offsetof(PREDICATELOCK, targetLink));
4393 
4394  if (predlock->tag.myXact != MySerializableXact
4396  {
4398  }
4399 
4400  predlock = nextpredlock;
4401  }
4402  }
4403 
4404  /* Release locks in reverse order */
4405  LWLockRelease(SerializableXactHashLock);
4406  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
4408  LWLockRelease(SerializablePredicateLockListLock);
4409 }
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:404
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:629
static HTAB * PredicateLockTargetHash
Definition: predicate.c:380
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4419
static PredXactList PredXact
Definition: predicate.c:367
TransactionId SxactGlobalXmin
static bool SerializationNeededForWrite(Relation relation)
Definition: predicate.c:534
unsigned int Oid
Definition: postgres_ext.h:31
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
Form_pg_index rd_index
Definition: rel.h:155
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
Oid rd_id
Definition: rel.h:115
PREDICATELOCKTAG tag
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
RelFileNode rd_node
Definition: rel.h:85
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1353
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1343
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:248
int i
SERIALIZABLEXACT * myXact
static bool MyXactDidWrite
Definition: predicate.c:405
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define offsetof(type, field)
Definition: c.h:551
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:121
static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag)
static

Definition at line 4065 of file predicate.c.

References Assert, DecrementParentLocks(), SERIALIZABLEXACT::finishedBefore, FlagRWConflict(), GET_PREDICATELOCKTARGETTAG_OFFSET, GetTransactionSnapshot(), HASH_FIND, HASH_REMOVE, hash_search_with_hash_value(), InvalidSerializableXact, IsSubTransaction(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myXact, NULL, offsetof, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetTagHashCode, RemoveTargetIfNoLongerUsed(), RWConflictExists(), SHMQueueDelete(), SHMQueueNext(), SxactIsCommitted, SxactIsDoomed, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdPrecedes(), and PREDICATELOCK::xactLink.

Referenced by CheckForSerializableConflictIn().

4066 {
4067  uint32 targettaghash;
4068  LWLock *partitionLock;
4069  PREDICATELOCKTARGET *target;
4070  PREDICATELOCK *predlock;
4071  PREDICATELOCK *mypredlock = NULL;
4072  PREDICATELOCKTAG mypredlocktag;
4073 
4075 
4076  /*
4077  * The same hash and LW lock apply to the lock target and the lock itself.
4078  */
4079  targettaghash = PredicateLockTargetTagHashCode(targettag);
4080  partitionLock = PredicateLockHashPartitionLock(targettaghash);
4081  LWLockAcquire(partitionLock, LW_SHARED);
4082  target = (PREDICATELOCKTARGET *)
4084  targettag, targettaghash,
4085  HASH_FIND, NULL);
4086  if (!target)
4087  {
4088  /* Nothing has this target locked; we're done here. */
4089  LWLockRelease(partitionLock);
4090  return;
4091  }
4092 
4093  /*
4094  * Each lock for an overlapping transaction represents a conflict: a
4095  * rw-dependency in to this transaction.
4096  */
4097  predlock = (PREDICATELOCK *)
4098  SHMQueueNext(&(target->predicateLocks),
4099  &(target->predicateLocks),
4100  offsetof(PREDICATELOCK, targetLink));
4101  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4102  while (predlock)
4103  {
4104  SHM_QUEUE *predlocktargetlink;
4105  PREDICATELOCK *nextpredlock;
4106  SERIALIZABLEXACT *sxact;
4107 
4108  predlocktargetlink = &(predlock->targetLink);
4109  nextpredlock = (PREDICATELOCK *)
4110  SHMQueueNext(&(target->predicateLocks),
4111  predlocktargetlink,
4112  offsetof(PREDICATELOCK, targetLink));
4113 
4114  sxact = predlock->tag.myXact;
4115  if (sxact == MySerializableXact)
4116  {
4117  /*
4118  * If we're getting a write lock on a tuple, we don't need a
4119  * predicate (SIREAD) lock on the same tuple. We can safely remove
4120  * our SIREAD lock, but we'll defer doing so until after the loop
4121  * because that requires upgrading to an exclusive partition lock.
4122  *
4123  * We can't use this optimization within a subtransaction because
4124  * the subtransaction could roll back, and we would be left
4125  * without any lock at the top level.
4126  */
4127  if (!IsSubTransaction()
4128  && GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
4129  {
4130  mypredlock = predlock;
4131  mypredlocktag = predlock->tag;
4132  }
4133  }
4134  else if (!SxactIsDoomed(sxact)
4135  && (!SxactIsCommitted(sxact)
4137  sxact->finishedBefore))
4139  {
4140  LWLockRelease(SerializableXactHashLock);
4141  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4142 
4143  /*
4144  * Re-check after getting exclusive lock because the other
4145  * transaction may have flagged a conflict.
4146  */
4147  if (!SxactIsDoomed(sxact)
4148  && (!SxactIsCommitted(sxact)
4150  sxact->finishedBefore))
4152  {
4154  }
4155 
4156  LWLockRelease(SerializableXactHashLock);
4157  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4158  }
4159 
4160  predlock = nextpredlock;
4161  }
4162  LWLockRelease(SerializableXactHashLock);
4163  LWLockRelease(partitionLock);
4164 
4165  /*
4166  * If we found one of our own SIREAD locks to remove, remove it now.
4167  *
4168  * At this point our transaction already has an ExclusiveRowLock on the
4169  * relation, so we are OK to drop the predicate lock on the tuple, if
4170  * found, without fearing that another write against the tuple will occur
4171  * before the MVCC information makes it to the buffer.
4172  */
4173  if (mypredlock != NULL)
4174  {
4175  uint32 predlockhashcode;
4176  PREDICATELOCK *rmpredlock;
4177 
4178  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
4179  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4180  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4181 
4182  /*
4183  * Remove the predicate lock from shared memory, if it wasn't removed
4184  * while the locks were released. One way that could happen is from
4185  * autovacuum cleaning up an index.
4186  */
4187  predlockhashcode = PredicateLockHashCodeFromTargetHashCode
4188  (&mypredlocktag, targettaghash);
4189  rmpredlock = (PREDICATELOCK *)
4191  &mypredlocktag,
4192  predlockhashcode,
4193  HASH_FIND, NULL);
4194  if (rmpredlock != NULL)
4195  {
4196  Assert(rmpredlock == mypredlock);
4197 
4198  SHMQueueDelete(&(mypredlock->targetLink));
4199  SHMQueueDelete(&(mypredlock->xactLink));
4200 
4201  rmpredlock = (PREDICATELOCK *)
4203  &mypredlocktag,
4204  predlockhashcode,
4205  HASH_REMOVE, NULL);
4206  Assert(rmpredlock == mypredlock);
4207 
4208  RemoveTargetIfNoLongerUsed(target, targettaghash);
4209  }
4210 
4211  LWLockRelease(SerializableXactHashLock);
4212  LWLockRelease(partitionLock);
4213  LWLockRelease(SerializablePredicateLockListLock);
4214 
4215  if (rmpredlock != NULL)
4216  {
4217  /*
4218  * Remove entry in local lock table if it exists. It's OK if it
4219  * doesn't exist; that means the lock was transferred to a new
4220  * target by a different backend.
4221  */
4223  targettag, targettaghash,
4224  HASH_REMOVE, NULL);
4225 
4226  DecrementParentLocks(targettag);
4227  }
4228  }
4229 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:898
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:404
TransactionId finishedBefore
Definition: lwlock.h:32
static bool RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Definition: predicate.c:629
static HTAB * PredicateLockTargetHash
Definition: predicate.c:380
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4419
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2028
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:300
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:245
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define SxactIsDoomed(sxact)
Definition: predicate.c:267
#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag)
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:302
static HTAB * PredicateLockHash
Definition: predicate.c:381
#define InvalidSerializableXact
unsigned int uint32
Definition: c.h:265
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2233
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:289
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
static HTAB * LocalPredicateLockHash
Definition: predicate.c:397
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
bool IsSubTransaction(void)
Definition: xact.c:4374
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
SERIALIZABLEXACT * myXact
#define SxactIsCommitted(sxact)
Definition: predicate.c:264
#define offsetof(type, field)
Definition: c.h:551
static void ClearOldPredicateLocks ( void  )
static

Definition at line 3503 of file predicate.c.

References Assert, PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, PREDICATELOCK::commitSeqNo, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, HASH_REMOVE, hash_search_with_hash_value(), PredXactListData::HavePartialClearedThrough, InvalidSerCommitSeqNo, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, NULL, offsetof, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, ReleaseOneSerializableXact(), RemoveTargetIfNoLongerUsed(), SHMQueueDelete(), SHMQueueNext(), PredXactListData::SxactGlobalXmin, SxactIsReadOnly, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdIsValid, TransactionIdPrecedesOrEquals(), and PREDICATELOCK::xactLink.

Referenced by ReleasePredicateLocks().

3504 {
3505  SERIALIZABLEXACT *finishedSxact;
3506  PREDICATELOCK *predlock;
3507 
3508  /*
3509  * Loop through finished transactions. They are in commit order, so we can
3510  * stop as soon as we find one that's still interesting.
3511  */
3512  LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
3513  finishedSxact = (SERIALIZABLEXACT *)
3516  offsetof(SERIALIZABLEXACT, finishedLink));
3517  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3518  while (finishedSxact)
3519  {
3520  SERIALIZABLEXACT *nextSxact;
3521 
3522  nextSxact = (SERIALIZABLEXACT *)
3524  &(finishedSxact->finishedLink),
3525  offsetof(SERIALIZABLEXACT, finishedLink));
3529  {
3530  /*
3531  * This transaction committed before any in-progress transaction
3532  * took its snapshot. It's no longer interesting.
3533  */
3534  LWLockRelease(SerializableXactHashLock);
3535  SHMQueueDelete(&(finishedSxact->finishedLink));
3536  ReleaseOneSerializableXact(finishedSxact, false, false);
3537  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3538  }
3539  else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
3540  && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
3541  {
3542  /*
3543  * Any active transactions that took their snapshot before this
3544  * transaction committed are read-only, so we can clear part of
3545  * its state.
3546  */
3547  LWLockRelease(SerializableXactHashLock);
3548 
3549  if (SxactIsReadOnly(finishedSxact))
3550  {
3551  /* A read-only transaction can be removed entirely */
3552  SHMQueueDelete(&(finishedSxact->finishedLink));
3553  ReleaseOneSerializableXact(finishedSxact, false, false);
3554  }
3555  else
3556  {
3557  /*
3558  * A read-write transaction can only be partially cleared. We
3559  * need to keep the SERIALIZABLEXACT but can release the
3560  * SIREAD locks and conflicts in.
3561  */
3562  ReleaseOneSerializableXact(finishedSxact, true, false);
3563  }
3564 
3566  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3567  }
3568  else
3569  {
3570  /* Still interesting. */
3571  break;
3572  }
3573  finishedSxact = nextSxact;
3574  }
3575  LWLockRelease(SerializableXactHashLock);
3576 
3577  /*
3578  * Loop through predicate locks on dummy transaction for summarized data.
3579  */
3580  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
3581  predlock = (PREDICATELOCK *)
3584  offsetof(PREDICATELOCK, xactLink));
3585  while (predlock)
3586  {
3587  PREDICATELOCK *nextpredlock;
3588  bool canDoPartialCleanup;
3589 
3590  nextpredlock = (PREDICATELOCK *)
3592  &predlock->xactLink,
3593  offsetof(PREDICATELOCK, xactLink));
3594 
3595  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3596  Assert(predlock->commitSeqNo != 0);
3598  canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
3599  LWLockRelease(SerializableXactHashLock);
3600 
3601  /*
3602  * If this lock originally belonged to an old enough transaction, we
3603  * can release it.
3604  */
3605  if (canDoPartialCleanup)
3606  {
3607  PREDICATELOCKTAG tag;
3608  PREDICATELOCKTARGET *target;
3609  PREDICATELOCKTARGETTAG targettag;
3610  uint32 targettaghash;
3611  LWLock *partitionLock;
3612 
3613  tag = predlock->tag;
3614  target = tag.myTarget;
3615  targettag = target->tag;
3616  targettaghash = PredicateLockTargetTagHashCode(&targettag);
3617  partitionLock = PredicateLockHashPartitionLock(targettaghash);
3618 
3619  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3620 
3621  SHMQueueDelete(&(predlock->targetLink));
3622  SHMQueueDelete(&(predlock->xactLink));
3623 
3626  targettaghash),
3627  HASH_REMOVE, NULL);
3628  RemoveTargetIfNoLongerUsed(target, targettaghash);
3629 
3630  LWLockRelease(partitionLock);
3631  }
3632 
3633  predlock = nextpredlock;
3634  }
3635 
3636  LWLockRelease(SerializablePredicateLockListLock);
3637  LWLockRelease(SerializableFinishedListLock);
3638 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:898
#define SxactIsReadOnly(sxact)
Definition: predicate.c:268
TransactionId finishedBefore
Definition: lwlock.h:32
static PredXactList PredXact
Definition: predicate.c:367
TransactionId SxactGlobalXmin
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2028
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:245
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:302
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
static HTAB * PredicateLockHash
Definition: predicate.c:381
unsigned int uint32
Definition: c.h:265
#define InvalidSerCommitSeqNo
SerCommitSeqNo commitSeqNo
SerCommitSeqNo HavePartialClearedThrough
PREDICATELOCKTAG tag
SerCommitSeqNo CanPartialClearThrough
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:289
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
SerCommitSeqNo commitSeqNo
#define NULL
Definition: c.h:226
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial, bool summarize)
Definition: predicate.c:3660
#define Assert(condition)
Definition: c.h:671
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:352
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static SHM_QUEUE * FinishedSerializableTransactions
Definition: predicate.c:382
#define offsetof(type, field)
Definition: c.h:551
PREDICATELOCKTARGET * myTarget
static bool CoarserLockCovers ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 1956 of file predicate.c.

References GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

1957 {
1958  PREDICATELOCKTARGETTAG targettag,
1959  parenttag;
1960 
1961  targettag = *newtargettag;
1962 
1963  /* check parents iteratively until no more */
1964  while (GetParentPredicateLockTag(&targettag, &parenttag))
1965  {
1966  targettag = parenttag;
1967  if (PredicateLockExists(&targettag))
1968  return true;
1969  }
1970 
1971  /* no more parents to check; lock is not covered */
1972  return false;
1973 }
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:1890
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:1917
static void CreatePredicateLock ( const PREDICATELOCKTARGETTAG targettag,
uint32  targettaghash,
SERIALIZABLEXACT sxact 
)
static

Definition at line 2295 of file predicate.c.

References PREDICATELOCK::commitSeqNo, ereport, errcode(), errhint(), errmsg(), ERROR, HASH_ENTER_NULL, hash_search_with_hash_value(), InvalidSerCommitSeqNo, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, SHMQueueInit(), SHMQueueInsertBefore(), PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by predicatelock_twophase_recover(), and PredicateLockAcquire().

2298 {
2299  PREDICATELOCKTARGET *target;
2300  PREDICATELOCKTAG locktag;
2301  PREDICATELOCK *lock;
2302  LWLock *partitionLock;
2303  bool found;
2304 
2305  partitionLock = PredicateLockHashPartitionLock(targettaghash);
2306 
2307  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
2308  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2309 
2310  /* Make sure that the target is represented. */
2311  target = (PREDICATELOCKTARGET *)
2313  targettag, targettaghash,
2314  HASH_ENTER_NULL, &found);
2315  if (!target)
2316  ereport(ERROR,
2317  (errcode(ERRCODE_OUT_OF_MEMORY),
2318  errmsg("out of shared memory"),
2319  errhint("You might need to increase max_pred_locks_per_transaction.")));
2320  if (!found)
2321  SHMQueueInit(&(target->predicateLocks));
2322 
2323  /* We've got the sxact and target, make sure they're joined. */
2324  locktag.myTarget = target;
2325  locktag.myXact = sxact;
2326  lock = (PREDICATELOCK *)
2328  PredicateLockHashCodeFromTargetHashCode(&locktag, targettaghash),
2329  HASH_ENTER_NULL, &found);
2330  if (!lock)
2331  ereport(ERROR,
2332  (errcode(ERRCODE_OUT_OF_MEMORY),
2333  errmsg("out of shared memory"),
2334  errhint("You might need to increase max_pred_locks_per_transaction.")));
2335 
2336  if (!found)
2337  {
2338  SHMQueueInsertBefore(&(target->predicateLocks), &(lock->targetLink));
2340  &(lock->xactLink));
2342  }
2343 
2344  LWLockRelease(partitionLock);
2345  LWLockRelease(SerializablePredicateLockListLock);
2346 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:898
Definition: lwlock.h:32
static HTAB * PredicateLockTargetHash
Definition: predicate.c:380
int errhint(const char *fmt,...)
Definition: elog.c:987
int errcode(int sqlerrcode)
Definition: elog.c:575
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:245
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:302
#define ERROR
Definition: elog.h:43
static HTAB * PredicateLockHash
Definition: predicate.c:381
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvalidSerCommitSeqNo
SerCommitSeqNo commitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
int errmsg(const char *fmt,...)
Definition: elog.c:797
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
SERIALIZABLEXACT * myXact
PREDICATELOCKTARGET * myTarget
static SERIALIZABLEXACT * CreatePredXact ( void  )
static

Definition at line 556 of file predicate.c.

References PredXactListData::activeList, PredXactListData::availableList, PredXactListElementData::link, NULL, offsetof, SHMQueueDelete(), SHMQueueInsertBefore(), SHMQueueNext(), and PredXactListElementData::sxact.

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

557 {
558  PredXactListElement ptle;
559 
560  ptle = (PredXactListElement)
564  if (!ptle)
565  return NULL;
566 
567  SHMQueueDelete(&ptle->link);
569  return &ptle->sxact;
570 }
static PredXactList PredXact
Definition: predicate.c:367
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define NULL
Definition: c.h:226
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
struct PredXactListElementData * PredXactListElement
#define offsetof(type, field)
Definition: c.h:551
static void DecrementParentLocks ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2233 of file predicate.c.

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

Referenced by CheckTargetForConflictsIn(), and DeleteChildTargetLocks().

2234 {
2235  PREDICATELOCKTARGETTAG parenttag,
2236  nexttag;
2237 
2238  parenttag = *targettag;
2239 
2240  while (GetParentPredicateLockTag(&parenttag, &nexttag))
2241  {
2242  uint32 targettaghash;
2243  LOCALPREDICATELOCK *parentlock,
2244  *rmlock PG_USED_FOR_ASSERTS_ONLY;
2245 
2246  parenttag = nexttag;
2247  targettaghash = PredicateLockTargetTagHashCode(&parenttag);
2248  parentlock = (LOCALPREDICATELOCK *)
2250  &parenttag, targettaghash,
2251  HASH_FIND, NULL);
2252 
2253  /*
2254  * There's a small chance the parent lock doesn't exist in the lock
2255  * table. This can happen if we prematurely removed it because an
2256  * index split caused the child refcount to be off.
2257  */
2258  if (parentlock == NULL)
2259  continue;
2260 
2261  parentlock->childLocks--;
2262 
2263  /*
2264  * Under similar circumstances the parent lock's refcount might be
2265  * zero. This only happens if we're holding that lock (otherwise we
2266  * would have removed the entry).
2267  */
2268  if (parentlock->childLocks < 0)
2269  {
2270  Assert(parentlock->held);
2271  parentlock->childLocks = 0;
2272  }
2273 
2274  if ((parentlock->childLocks == 0) && (!parentlock->held))
2275  {
2276  rmlock = (LOCALPREDICATELOCK *)
2278  &parenttag, targettaghash,
2279  HASH_REMOVE, NULL);
2280  Assert(rmlock == parentlock);
2281  }
2282  }
2283 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:898
unsigned int uint32
Definition: c.h:265
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:289
static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag, PREDICATELOCKTARGETTAG *parent)
Definition: predicate.c:1917
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
static HTAB * LocalPredicateLockHash
Definition: predicate.c:397
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:986
static void DeleteChildTargetLocks ( const PREDICATELOCKTARGETTAG newtargettag)
static

Definition at line 2057 of file predicate.c.

References Assert, DecrementParentLocks(), HASH_REMOVE, hash_search_with_hash_value(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MySerializableXact, PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, NULL, offsetof, PG_USED_FOR_ASSERTS_ONLY, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, RemoveTargetIfNoLongerUsed(), SHMQueueDelete(), SHMQueueNext(), PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TargetTagIsCoveredBy, and PREDICATELOCK::xactLink.

Referenced by PredicateLockAcquire().

2058 {
2059  SERIALIZABLEXACT *sxact;
2060  PREDICATELOCK *predlock;
2061 
2062  LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
2063  sxact = MySerializableXact;
2064  predlock = (PREDICATELOCK *)
2065  SHMQueueNext(&(sxact->predicateLocks),
2066  &(sxact->predicateLocks),
2067  offsetof(PREDICATELOCK, xactLink));
2068  while (predlock)
2069  {
2070  SHM_QUEUE *predlocksxactlink;
2071  PREDICATELOCK *nextpredlock;
2072  PREDICATELOCKTAG oldlocktag;
2073  PREDICATELOCKTARGET *oldtarget;
2074  PREDICATELOCKTARGETTAG oldtargettag;
2075 
2076  predlocksxactlink = &(predlock->xactLink);
2077  nextpredlock = (PREDICATELOCK *)
2078  SHMQueueNext(&(sxact->predicateLocks),
2079  predlocksxactlink,
2080  offsetof(PREDICATELOCK, xactLink));
2081 
2082  oldlocktag = predlock->tag;
2083  Assert(oldlocktag.myXact == sxact);
2084  oldtarget = oldlocktag.myTarget;
2085  oldtargettag = oldtarget->tag;
2086 
2087  if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
2088  {
2089  uint32 oldtargettaghash;
2090  LWLock *partitionLock;
2092 
2093  oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
2094  partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
2095 
2096  LWLockAcquire(partitionLock, LW_EXCLUSIVE);
2097 
2098  SHMQueueDelete(predlocksxactlink);
2099  SHMQueueDelete(&(predlock->targetLink));
2100  rmpredlock = hash_search_with_hash_value
2102  &oldlocktag,
2104  oldtargettaghash),
2105  HASH_REMOVE, NULL);
2106  Assert(rmpredlock == predlock);
2107 
2108  RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
2109 
2110  LWLockRelease(partitionLock);
2111 
2112  DecrementParentLocks(&oldtargettag);
2113  }
2114 
2115  predlock = nextpredlock;
2116  }
2117  LWLockRelease(SerializablePredicateLockListLock);
2118 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:898
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:404
Definition: lwlock.h:32
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2028
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:245
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:302
static HTAB * PredicateLockHash
Definition: predicate.c:381
unsigned int uint32
Definition: c.h:265
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:2233
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:289
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
PREDICATELOCKTARGETTAG tag
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
#define TargetTagIsCoveredBy(covered_target, covering_target)
Definition: predicate.c:220
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
SERIALIZABLEXACT * myXact
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:986
#define offsetof(type, field)
Definition: c.h:551
PREDICATELOCKTARGET * myTarget
static void DeleteLockTarget ( PREDICATELOCKTARGET target,
uint32  targettaghash 
)
static

Definition at line 2525 of file predicate.c.

References Assert, HASH_REMOVE, hash_search_with_hash_value(), LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), offsetof, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PREDICATELOCKTARGET::predicateLocks, RemoveTargetIfNoLongerUsed(), SHMQueueDelete(), SHMQueueNext(), PREDICATELOCK::tag, PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by TransferPredicateLocksToNewTarget().

2526 {
2527  PREDICATELOCK *predlock;
2528  SHM_QUEUE *predlocktargetlink;
2529  PREDICATELOCK *nextpredlock;
2530  bool found;
2531 
2532  Assert(LWLockHeldByMe(SerializablePredicateLockListLock));
2534 
2535  predlock = (PREDICATELOCK *)
2536  SHMQueueNext(&(target->predicateLocks),
2537  &(target->predicateLocks),
2538  offsetof(PREDICATELOCK, targetLink));
2539  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2540  while (predlock)
2541  {
2542  predlocktargetlink = &(predlock->targetLink);
2543  nextpredlock = (PREDICATELOCK *)
2544  SHMQueueNext(&(target->predicateLocks),
2545  predlocktargetlink,
2546  offsetof(PREDICATELOCK, targetLink));
2547 
2548  SHMQueueDelete(&(predlock->xactLink));
2549  SHMQueueDelete(&(predlock->targetLink));
2550 
2553  &predlock->tag,
2555  targettaghash),
2556  HASH_REMOVE, &found);
2557  Assert(found);
2558 
2559  predlock = nextpredlock;
2560  }
2561  LWLockRelease(SerializableXactHashLock);
2562 
2563  /* Remove the target itself, if possible. */
2564  RemoveTargetIfNoLongerUsed(target, targettaghash);
2565 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:898
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1830
static void RemoveTargetIfNoLongerUsed(PREDICATELOCKTARGET *target, uint32 targettaghash)
Definition: predicate.c:2028
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:245
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:302
static HTAB * PredicateLockHash
Definition: predicate.c:381
PREDICATELOCKTAG tag
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:671
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
#define offsetof(type, field)
Definition: c.h:551
static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
)
static

Definition at line 2811 of file predicate.c.

References Assert, PREDICATELOCK::commitSeqNo, RelFileNode::dbNode, 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, NULL, NUM_PREDICATELOCK_PARTITIONS, offsetof, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLockByIndex, PredicateLockingNeededForRelation(), SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetTagHashCode, PREDLOCKTAG_RELATION, RelationData::rd_id, RelationData::rd_index, RelationData::rd_node, RemoveScratchTarget(), RestoreScratchTarget(), SET_PREDICATELOCKTARGETTAG_RELATION, SHMQueueDelete(), SHMQueueInit(), SHMQueueInsertBefore(), SHMQueueNext(), PredXactListData::SxactGlobalXmin, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdIsValid, and PREDICATELOCK::xactLink.

Referenced by TransferPredicateLocksToHeapRelation().

2812 {
2813  HASH_SEQ_STATUS seqstat;
2814  PREDICATELOCKTARGET *oldtarget;
2815  PREDICATELOCKTARGET *heaptarget;
2816  Oid dbId;
2817  Oid relId;
2818  Oid heapId;
2819  int i;
2820  bool isIndex;
2821  bool found;
2822  uint32 heaptargettaghash;
2823 
2824  /*
2825  * Bail out quickly if there are no serializable transactions running.
2826  * It's safe to check this without taking locks because the caller is
2827  * holding an ACCESS EXCLUSIVE lock on the relation. No new locks which
2828  * would matter here can be acquired while that is held.
2829  */
2831  return;
2832 
2833  if (!PredicateLockingNeededForRelation(relation))
2834  return;
2835 
2836  dbId = relation->rd_node.dbNode;
2837  relId = relation->rd_id;
2838  if (relation->rd_index == NULL)
2839  {
2840  isIndex = false;
2841  heapId = relId;
2842  }
2843  else
2844  {
2845  isIndex = true;
2846  heapId = relation->rd_index->indrelid;
2847  }
2848  Assert(heapId != InvalidOid);
2849  Assert(transfer || !isIndex); /* index OID only makes sense with
2850  * transfer */
2851 
2852  /* Retrieve first time needed, then keep. */
2853  heaptargettaghash = 0;
2854  heaptarget = NULL;
2855 
2856  /* Acquire locks on all lock partitions */
2857  LWLockAcquire(SerializablePredicateLockListLock, LW_EXCLUSIVE);
2858  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
2860  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
2861 
2862  /*
2863  * Remove the dummy entry to give us scratch space, so we know we'll be
2864  * able to create the new lock target.
2865  */
2866  if (transfer)
2867  RemoveScratchTarget(true);
2868 
2869  /* Scan through target map */
2871 
2872  while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
2873  {
2874  PREDICATELOCK *oldpredlock;
2875 
2876  /*
2877  * Check whether this is a target which needs attention.
2878  */
2879  if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) != relId)
2880  continue; /* wrong relation id */
2881  if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
2882  continue; /* wrong database id */
2883  if (transfer && !isIndex
2885  continue; /* already the right lock */
2886 
2887  /*
2888  * If we made it here, we have work to do. We make sure the heap
2889  * relation lock exists, then we walk the list of predicate locks for
2890  * the old target we found, moving all locks to the heap relation lock
2891  * -- unless they already hold that.
2892  */
2893 
2894  /*
2895  * First make sure we have the heap relation target. We only need to
2896  * do this once.
2897  */
2898  if (transfer && heaptarget == NULL)
2899  {
2900  PREDICATELOCKTARGETTAG heaptargettag;
2901 
2902  SET_PREDICATELOCKTARGETTAG_RELATION(heaptargettag, dbId, heapId);
2903  heaptargettaghash = PredicateLockTargetTagHashCode(&heaptargettag);
2905  &heaptargettag,
2906  heaptargettaghash,
2907  HASH_ENTER, &found);
2908  if (!found)
2909  SHMQueueInit(&heaptarget->predicateLocks);
2910  }
2911 
2912  /*
2913  * Loop through all the locks on the old target, replacing them with
2914  * locks on the new target.
2915  */
2916  oldpredlock = (PREDICATELOCK *)
2917  SHMQueueNext(&(oldtarget->predicateLocks),
2918  &(oldtarget->predicateLocks),
2919  offsetof(PREDICATELOCK, targetLink));
2920  while (oldpredlock)
2921  {
2922  PREDICATELOCK *nextpredlock;
2923  PREDICATELOCK *newpredlock;
2924  SerCommitSeqNo oldCommitSeqNo;
2925  SERIALIZABLEXACT *oldXact;
2926 
2927  nextpredlock = (PREDICATELOCK *)
2928  SHMQueueNext(&(oldtarget->predicateLocks),
2929  &(oldpredlock->targetLink),
2930  offsetof(PREDICATELOCK, targetLink));
2931 
2932  /*
2933  * Remove the old lock first. This avoids the chance of running
2934  * out of lock structure entries for the hash table.
2935  */
2936  oldCommitSeqNo = oldpredlock->commitSeqNo;
2937  oldXact = oldpredlock->tag.myXact;
2938 
2939  SHMQueueDelete(&(oldpredlock->xactLink));
2940 
2941  /*
2942  * No need for retail delete from oldtarget list, we're removing
2943  * the whole target anyway.
2944  */
2946  &oldpredlock->tag,
2947  HASH_REMOVE, &found);
2948  Assert(found);
2949 
2950  if (transfer)
2951  {
2952  PREDICATELOCKTAG newpredlocktag;
2953 
2954  newpredlocktag.myTarget = heaptarget;
2955  newpredlocktag.myXact = oldXact;
2956  newpredlock = (PREDICATELOCK *)
2958  &newpredlocktag,
2960  heaptargettaghash),
2961  HASH_ENTER,
2962  &found);
2963  if (!found)
2964  {
2965  SHMQueueInsertBefore(&(heaptarget->predicateLocks),
2966  &(newpredlock->targetLink));
2967  SHMQueueInsertBefore(&(newpredlocktag.myXact->predicateLocks),
2968  &(newpredlock->xactLink));
2969  newpredlock->commitSeqNo = oldCommitSeqNo;
2970  }
2971  else
2972  {
2973  if (newpredlock->commitSeqNo < oldCommitSeqNo)
2974  newpredlock->commitSeqNo = oldCommitSeqNo;
2975  }
2976 
2977  Assert(newpredlock->commitSeqNo != 0);
2978  Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
2979  || (newpredlock->tag.myXact == OldCommittedSxact));
2980  }
2981 
2982  oldpredlock = nextpredlock;
2983  }
2984 
2986  &found);
2987  Assert(found);
2988  }
2989 
2990  /* Put the scratch entry back */
2991  if (transfer)
2992  RestoreScratchTarget(true);
2993 
2994  /* Release locks in reverse order */
2995  LWLockRelease(SerializableXactHashLock);
2996  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
2998  LWLockRelease(SerializablePredicateLockListLock);
2999 }
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:898
static bool PredicateLockingNeededForRelation(Relation relation)
Definition: predicate.c:471
static HTAB * PredicateLockTargetHash
Definition: predicate.c:380
static PredXactList PredXact
Definition: predicate.c:367
TransactionId SxactGlobalXmin
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
unsigned int Oid
Definition: postgres_ext.h:31
#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag, dboid, reloid)
static void RemoveScratchTarget(bool lockheld)
Definition: predicate.c:1985
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
Form_pg_index rd_index
Definition: rel.h:155
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:302
static HTAB * PredicateLockHash
Definition: predicate.c:381
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
unsigned int uint32
Definition: c.h:265
Oid rd_id
Definition: rel.h:115
#define InvalidSerCommitSeqNo
static void RestoreScratchTarget(bool lockheld)
Definition: predicate.c:2006
PREDICATELOCKTAG tag
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:289
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define InvalidOid
Definition: postgres_ext.h:36
PREDICATELOCKTARGETTAG tag
RelFileNode rd_node
Definition: rel.h:85
SerCommitSeqNo commitSeqNo
uint64 SerCommitSeqNo
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1353
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1343
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:352
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:248
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
int i
void SHMQueueDelete(SHM_QUEUE *queue)
Definition: shmqueue.c:68
SERIALIZABLEXACT * myXact
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define offsetof(type, field)
Definition: c.h:551
PREDICATELOCKTARGET * myTarget
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:121
static SERIALIZABLEXACT * FirstPredXact ( void  )
static

Definition at line 588 of file predicate.c.

References PredXactListData::activeList, NULL, offsetof, SHMQueueNext(), and PredXactListElementData::sxact.

Referenced by GetSerializableTransactionSnapshotInt(), and SetNewSxactGlobalXmin().

589 {
590  PredXactListElement ptle;
591 
592  ptle = (PredXactListElement)
596  if (!ptle)
597  return NULL;
598 
599  return &ptle->sxact;
600 }
static PredXactList PredXact
Definition: predicate.c:367
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define NULL
Definition: c.h:226
struct PredXactListElementData * PredXactListElement
#define offsetof(type, field)
Definition: c.h:551
static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4419 of file predicate.c.

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

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

4420 {
4421  Assert(reader != writer);
4422 
4423  /* First, see if this conflict causes failure. */
4425 
4426  /* Actually do the conflict flagging. */
4427  if (reader == OldCommittedSxact)
4429  else if (writer == OldCommittedSxact)
4431  else
4432  SetRWConflict(reader, writer);
4433 }
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
static void SetRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:662
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer)
Definition: predicate.c:4454
#define Assert(condition)
Definition: c.h:671
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:352
#define SXACT_FLAG_SUMMARY_CONFLICT_IN
static void FlagSxactUnsafe ( SERIALIZABLEXACT sxact)
static

Definition at line 726 of file predicate.c.

References Assert, SERIALIZABLEXACT::flags, RWConflictData::inLink, offsetof, SERIALIZABLEXACT::possibleUnsafeConflicts, ReleaseRWConflict(), SHMQueueNext(), SXACT_FLAG_RO_UNSAFE, RWConflictData::sxactIn, SxactIsReadOnly, SxactIsROSafe, and RWConflictData::sxactOut.

Referenced by ReleasePredicateLocks().

727 {
728  RWConflict conflict,
729  nextConflict;
730 
731  Assert(SxactIsReadOnly(sxact));
732  Assert(!SxactIsROSafe(sxact));
733 
734  sxact->flags |= SXACT_FLAG_RO_UNSAFE;
735 
736  /*
737  * We know this isn't a safe snapshot, so we can stop looking for other
738  * potential conflicts.
739  */
740  conflict = (RWConflict)
742  &sxact->possibleUnsafeConflicts,
743  offsetof(RWConflictData, inLink));
744  while (conflict)
745  {
746  nextConflict = (RWConflict)
748  &conflict->inLink,
749  offsetof(RWConflictData, inLink));
750 
751  Assert(!SxactIsReadOnly(conflict->sxactOut));
752  Assert(sxact == conflict->sxactIn);
753 
754  ReleaseRWConflict(conflict);
755 
756  conflict = nextConflict;
757  }
758 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:268
struct RWConflictData * RWConflict
static void ReleaseRWConflict(RWConflict conflict)
Definition: predicate.c:718
SERIALIZABLEXACT * sxactIn
SHM_QUEUE possibleUnsafeConflicts
#define SxactIsROSafe(sxact)
Definition: predicate.c:278
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:671
#define SXACT_FLAG_RO_UNSAFE
#define offsetof(type, field)
Definition: c.h:551
SERIALIZABLEXACT * sxactOut
static bool GetParentPredicateLockTag ( const PREDICATELOCKTARGETTAG tag,
PREDICATELOCKTARGETTAG parent 
)
static

Definition at line 1917 of file predicate.c.

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

1919 {
1920  switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
1921  {
1922  case PREDLOCKTAG_RELATION:
1923  /* relation locks have no parent lock */
1924  return false;
1925 
1926  case PREDLOCKTAG_PAGE:
1927  /* parent lock is relation lock */
1931 
1932  return true;
1933 
1934  case PREDLOCKTAG_TUPLE:
1935  /* parent lock is page lock */
1940  return true;
1941  }
1942 
1943  /* not reachable */
1944  Assert(false);
1945  return false;
1946 }
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
#define GET_PREDICATELOCKTARGETTAG_PAGE(locktag)
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
#define SET_PREDICATELOCKTARGETTAG_RELATION(locktag, dboid, reloid)
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
#define Assert(condition)
Definition: c.h:671
PredicateLockData* GetPredicateLockStatusData ( void  )

Definition at line 1376 of file predicate.c.

References Assert, hash_get_num_entries(), hash_seq_init(), hash_seq_search(), i, PredicateLockData::locktags, LW_SHARED, LWLockAcquire(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, PredicateLockData::nelements, NUM_PREDICATELOCK_PARTITIONS, palloc(), PredicateLockHashPartitionLockByIndex, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, and PredicateLockData::xacts.

Referenced by pg_lock_status().

1377 {
1378  PredicateLockData *data;
1379  int i;
1380  int els,
1381  el;
1382  HASH_SEQ_STATUS seqstat;
1383  PREDICATELOCK *predlock;
1384 
1385  data = (PredicateLockData *) palloc(sizeof(PredicateLockData));
1386 
1387  /*
1388  * To ensure consistency, take simultaneous locks on all partition locks
1389  * in ascending order, then SerializableXactHashLock.
1390  */
1391  for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
1393  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
1394 
1395  /* Get number of locks and allocate appropriately-sized arrays. */
1397  data->nelements = els;
1398  data->locktags = (PREDICATELOCKTARGETTAG *)
1399  palloc(sizeof(PREDICATELOCKTARGETTAG) * els);
1400  data->xacts = (SERIALIZABLEXACT *)
1401  palloc(sizeof(SERIALIZABLEXACT) * els);
1402 
1403 
1404  /* Scan through PredicateLockHash and copy contents */
1405  hash_seq_init(&seqstat, PredicateLockHash);
1406 
1407  el = 0;
1408 
1409  while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
1410  {
1411  data->locktags[el] = predlock->tag.myTarget->tag;
1412  data->xacts[el] = *predlock->tag.myXact;
1413  el++;
1414  }
1415 
1416  Assert(el == els);
1417 
1418  /* Release locks in reverse order */
1419  LWLockRelease(SerializableXactHashLock);
1420  for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
1422 
1423  return data;
1424 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1297
SERIALIZABLEXACT * xacts
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
static HTAB * PredicateLockHash
Definition: predicate.c:381
PREDICATELOCKTARGETTAG * locktags
PREDICATELOCKTAG tag
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:671
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1353
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1343
#define PredicateLockHashPartitionLockByIndex(i)
Definition: predicate.c:248
void * palloc(Size size)
Definition: mcxt.c:891
int i
SERIALIZABLEXACT * myXact
PREDICATELOCKTARGET * myTarget
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:121
static Snapshot GetSafeSnapshot ( Snapshot  snapshot)
static

Definition at line 1491 of file predicate.c.

References Assert, DEBUG2, ereport, errcode(), errmsg(), SERIALIZABLEXACT::flags, GetSerializableTransactionSnapshotInt(), InvalidSerializableXact, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SERIALIZABLEXACT::possibleUnsafeConflicts, ProcWaitForSignal(), ReleasePredicateLocks(), SHMQueueEmpty(), SXACT_FLAG_DEFERRABLE_WAITING, SxactIsROSafe, SxactIsROUnsafe, WAIT_EVENT_SAFE_SNAPSHOT, XactDeferrable, and XactReadOnly.

Referenced by GetSerializableTransactionSnapshot().

1492 {
1493  Snapshot snapshot;
1494 
1496 
1497  while (true)
1498  {
1499  /*
1500  * GetSerializableTransactionSnapshotInt is going to call
1501  * GetSnapshotData, so we need to provide it the static snapshot area
1502  * our caller passed to us. The pointer returned is actually the same
1503  * one passed to it, but we avoid assuming that here.
1504  */
1505  snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
1507 
1509  return snapshot; /* no concurrent r/w xacts; it's safe */
1510 
1511  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1512 
1513  /*
1514  * Wait for concurrent transactions to finish. Stop early if one of
1515  * them marked us as conflicted.
1516  */
1520  {
1521  LWLockRelease(SerializableXactHashLock);
1523  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1524  }
1526 
1528  {
1529  LWLockRelease(SerializableXactHashLock);
1530  break; /* success */
1531  }
1532 
1533  LWLockRelease(SerializableXactHashLock);
1534 
1535  /* else, need to retry... */
1536  ereport(DEBUG2,
1537  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
1538  errmsg("deferrable snapshot was unsafe; trying a new one")));
1539  ReleasePredicateLocks(false);
1540  }
1541 
1542  /*
1543  * Now we have a safe snapshot, so we don't need to do any further checks.
1544  */
1546  ReleasePredicateLocks(false);
1547 
1548  return snapshot;
1549 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:404
bool XactDeferrable
Definition: xact.c:80
int errcode(int sqlerrcode)
Definition: elog.c:575
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
SHM_QUEUE possibleUnsafeConflicts
#define InvalidSerializableXact
#define SXACT_FLAG_DEFERRABLE_WAITING
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, TransactionId sourcexid)
Definition: predicate.c:1632
#define DEBUG2
Definition: elog.h:24
#define InvalidTransactionId
Definition: transam.h:31
#define SxactIsROSafe(sxact)
Definition: predicate.c:278
#define ereport(elevel, rest)
Definition: elog.h:122
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1739
bool SHMQueueEmpty(const SHM_QUEUE *queue)
Definition: shmqueue.c:180
void ReleasePredicateLocks(bool isCommit)
Definition: predicate.c:3185
bool XactReadOnly
Definition: xact.c:77
#define Assert(condition)
Definition: c.h:671
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define SxactIsROUnsafe(sxact)
Definition: predicate.c:279
Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot)

Definition at line 1563 of file predicate.c.

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

Referenced by GetTransactionSnapshot().

1564 {
1566 
1567  /*
1568  * Can't use serializable mode while recovery is still active, as it is,
1569  * for example, on a hot standby. We could get here despite the check in
1570  * check_XactIsoLevel() if default_transaction_isolation is set to
1571  * serializable, so phrase the hint accordingly.
1572  */
1573  if (RecoveryInProgress())
1574  ereport(ERROR,
1575  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1576  errmsg("cannot use serializable mode in a hot standby"),
1577  errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
1578  errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));
1579 
1580  /*
1581  * A special optimization is available for SERIALIZABLE READ ONLY
1582  * DEFERRABLE transactions -- we can wait for a suitable snapshot and
1583  * thereby avoid all SSI overhead once it's running.
1584  */
1586  return GetSafeSnapshot(snapshot);
1587 
1588  return GetSerializableTransactionSnapshotInt(snapshot,
1590 }
bool XactDeferrable
Definition: xact.c:80
int errhint(const char *fmt,...)
Definition: elog.c:987
static Snapshot GetSafeSnapshot(Snapshot snapshot)
Definition: predicate.c:1491
int errcode(int sqlerrcode)
Definition: elog.c:575
bool RecoveryInProgress(void)
Definition: xlog.c:7805
#define ERROR
Definition: elog.h:43
static Snapshot GetSerializableTransactionSnapshotInt(Snapshot snapshot, TransactionId sourcexid)
Definition: predicate.c:1632
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define InvalidTransactionId
Definition: transam.h:31
#define ereport(elevel, rest)
Definition: elog.h:122
bool XactReadOnly
Definition: xact.c:77
#define Assert(condition)
Definition: c.h:671
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define IsolationIsSerializable()
Definition: xact.h:44
static Snapshot GetSerializableTransactionSnapshotInt ( Snapshot  snapshot,
TransactionId  sourcexid 
)
static

Definition at line 1632 of file predicate.c.

References Assert, SERIALIZABLEXACT::commitSeqNo, CreatePredXact(), elog, HASHCTL::entrysize, ereport, errcode(), errdetail(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FirstPredXact(), SERIALIZABLEXACT::flags, GET_VXID_FROM_PGPROC, GetSnapshotData(), GetTopTransactionIdIfAny(), HASH_BLOBS, hash_create(), HASH_ELEM, SERIALIZABLEXACT::inConflicts, InvalidSerCommitSeqNo, InvalidSerializableXact, InvalidTransactionId, IsInParallelMode(), HASHCTL::keysize, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), max_predicate_locks_per_xact, max_prepared_xacts, MaxBackends, MemSet, MyProc, MyProcPid, MyXactDidWrite, NextPredXact(), NULL, OldSerXidSetActiveSerXmin(), SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::predicateLocks, SERIALIZABLEXACT::prepareSeqNo, ProcArrayInstallImportedXmin(), RecoveryInProgress(), ReleasePredXact(), SERIALIZABLEXACT::SeqNo, SetPossibleUnsafeConflict(), SHMQueueElemInit(), SHMQueueInit(), SummarizeOldestCommittedSxact(), SXACT_FLAG_READ_ONLY, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactIsCommitted, SxactIsDoomed, SxactIsReadOnly, SERIALIZABLEXACT::topXid, TransactionIdEquals, TransactionIdFollows(), TransactionIdIsValid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, XactReadOnly, SnapshotData::xmin, and SERIALIZABLEXACT::xmin.

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

1634 {
1635  PGPROC *proc;
1636  VirtualTransactionId vxid;
1637  SERIALIZABLEXACT *sxact,
1638  *othersxact;
1639  HASHCTL hash_ctl;
1640 
1641  /* We only do this for serializable transactions. Once. */
1643 
1645 
1646  /*
1647  * Since all parts of a serializable transaction must use the same
1648  * snapshot, it is too late to establish one after a parallel operation
1649  * has begun.
1650  */
1651  if (IsInParallelMode())
1652  elog(ERROR, "cannot establish serializable snapshot during a parallel operation");
1653 
1654  proc = MyProc;
1655  Assert(proc != NULL);
1656  GET_VXID_FROM_PGPROC(vxid, *proc);
1657 
1658  /*
1659  * First we get the sxact structure, which may involve looping and access
1660  * to the "finished" list to free a structure for use.
1661  *
1662  * We must hold SerializableXactHashLock when taking/checking the snapshot
1663  * to avoid race conditions, for much the same reasons that
1664  * GetSnapshotData takes the ProcArrayLock. Since we might have to
1665  * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
1666  * this means we have to create the sxact first, which is a bit annoying
1667  * (in particular, an elog(ERROR) in procarray.c would cause us to leak
1668  * the sxact). Consider refactoring to avoid this.
1669  */
1670 #ifdef TEST_OLDSERXID
1672 #endif
1673  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1674  do
1675  {
1676  sxact = CreatePredXact();
1677  /* If null, push out committed sxact to SLRU summary & retry. */
1678  if (!sxact)
1679  {
1680  LWLockRelease(SerializableXactHashLock);
1682  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
1683  }
1684  } while (!sxact);
1685 
1686  /* Get the snapshot, or check that it's safe to use */
1687  if (!TransactionIdIsValid(sourcexid))
1688  snapshot = GetSnapshotData(snapshot);
1689  else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcexid))
1690  {
1691  ReleasePredXact(sxact);
1692  LWLockRelease(SerializableXactHashLock);
1693  ereport(ERROR,
1694  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1695  errmsg("could not import the requested snapshot"),
1696  errdetail("The source transaction %u is not running anymore.",
1697  sourcexid)));
1698  }
1699 
1700  /*
1701  * If there are no serializable transactions which are not read-only, we
1702  * can "opt out" of predicate locking and conflict checking for a
1703  * read-only transaction.
1704  *
1705  * The reason this is safe is that a read-only transaction can only become
1706  * part of a dangerous structure if it overlaps a writable transaction
1707  * which in turn overlaps a writable transaction which committed before
1708  * the read-only transaction started. A new writable transaction can
1709  * overlap this one, but it can't meet the other condition of overlapping
1710  * a transaction which committed before this one started.
1711  */
1713  {
1714  ReleasePredXact(sxact);
1715  LWLockRelease(SerializableXactHashLock);
1716  return snapshot;
1717  }
1718 
1719  /* Maintain serializable global xmin info. */
1721  {
1723  PredXact->SxactGlobalXmin = snapshot->xmin;
1725  OldSerXidSetActiveSerXmin(snapshot->xmin);
1726  }
1727  else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
1728  {
1731  }
1732  else
1733  {
1735  }
1736 
1737  /* Initialize the structure. */
1738  sxact->vxid = vxid;
1742  SHMQueueInit(&(sxact->outConflicts));
1743  SHMQueueInit(&(sxact->inConflicts));
1745  sxact->topXid = GetTopTransactionIdIfAny();
1747  sxact->xmin = snapshot->xmin;
1748  sxact->pid = MyProcPid;
1749  SHMQueueInit(&(sxact->predicateLocks));
1750  SHMQueueElemInit(&(sxact->finishedLink));
1751  sxact->flags = 0;
1752  if (XactReadOnly)
1753  {
1754  sxact->flags |= SXACT_FLAG_READ_ONLY;
1755 
1756  /*
1757  * Register all concurrent r/w transactions as possible conflicts; if
1758  * all of them commit without any outgoing conflicts to earlier
1759  * transactions then this snapshot can be deemed safe (and we can run
1760  * without tracking predicate locks).
1761  */
1762  for (othersxact = FirstPredXact();
1763  othersxact != NULL;
1764  othersxact = NextPredXact(othersxact))
1765  {
1766  if (!SxactIsCommitted(othersxact)
1767  && !SxactIsDoomed(othersxact)
1768  && !SxactIsReadOnly(othersxact))
1769  {
1770  SetPossibleUnsafeConflict(sxact, othersxact);
1771  }
1772  }
1773  }
1774  else
1775  {
1779  }
1780 
1781  MySerializableXact = sxact;
1782  MyXactDidWrite = false; /* haven't written anything yet */
1783 
1784  LWLockRelease(SerializableXactHashLock);
1785 
1786  /* Initialize the backend-local hash table of parent locks */
1788  MemSet(&hash_ctl, 0, sizeof(hash_ctl));
1789  hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
1790  hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
1791  LocalPredicateLockHash = hash_create("Local predicate lock",
1793  &hash_ctl,
1794  HASH_ELEM | HASH_BLOBS);
1795 
1796  return snapshot;
1797 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:268
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:404
TransactionId finishedBefore
bool ProcArrayInstallImportedXmin(TransactionId xmin, TransactionId sourcexid)
Definition: procarray.c:1791
int MyProcPid
Definition: globals.c:38
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:81
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
#define HASH_ELEM
Definition: hsearch.h:87
PGPROC * MyProc
Definition: proc.c:67
static PredXactList PredXact
Definition: predicate.c:367
TransactionId SxactGlobalXmin
Size entrysize
Definition: hsearch.h:73
int errcode(int sqlerrcode)
Definition: elog.c:575
#define MemSet(start, val, len)
Definition: c.h:853
bool RecoveryInProgress(void)
Definition: xlog.c:7805
int max_predicate_locks_per_xact
Definition: predicate.c:356
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define SxactIsDoomed(sxact)
Definition: predicate.c:267
bool IsInParallelMode(void)
Definition: xact.c:912
SHM_QUEUE possibleUnsafeConflicts
#define ERROR
Definition: elog.h:43
int max_prepared_xacts
Definition: twophase.c:98
union SERIALIZABLEXACT::@56 SeqNo
#define InvalidSerializableXact
static void ReleasePredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:573
int MaxBackends
Definition: globals.c:126
struct LOCALPREDICATELOCK LOCALPREDICATELOCK
VirtualTransactionId vxid
static SERIALIZABLEXACT * NextPredXact(SERIALIZABLEXACT *sxact)
Definition: predicate.c:603
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define InvalidTransactionId
Definition: transam.h:31
TransactionId xmin
Definition: snapshot.h:66
SerCommitSeqNo lastCommitBeforeSnapshot
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:403
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvalidSerCommitSeqNo
static SERIALIZABLEXACT * FirstPredXact(void)
Definition: predicate.c:588
SerCommitSeqNo commitSeqNo
#define HASH_BLOBS
Definition: hsearch.h:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:301
Size keysize
Definition: hsearch.h:72
bool XactReadOnly
Definition: xact.c:77
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
static void OldSerXidSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:981
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
SerCommitSeqNo prepareSeqNo
Snapshot GetSnapshotData(Snapshot snapshot)
Definition: procarray.c:1503
static HTAB * LocalPredicateLockHash
Definition: predicate.c:397
SerCommitSeqNo LastSxactCommitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
void SHMQueueElemInit(SHM_QUEUE *queue)
Definition: shmqueue.c:57
int errmsg(const char *fmt,...)
Definition: elog.c:797
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
static void SetPossibleUnsafeConflict(SERIALIZABLEXACT *roXact, SERIALIZABLEXACT *activeXact)
Definition: predicate.c:688
#define SXACT_FLAG_READ_ONLY
static void SummarizeOldestCommittedSxact(void)
Definition: predicate.c:1434
static bool MyXactDidWrite
Definition: predicate.c:405
#define elog
Definition: elog.h:219
#define TransactionIdIsValid(xid)
Definition: transam.h:41
Definition: proc.h:84
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:556
#define SxactIsCommitted(sxact)
Definition: predicate.c:264
void InitPredicateLocks ( void  )

Definition at line 1097 of file predicate.c.

References PredXactListData::activeList, PredXactListData::availableList, RWConflictPoolHeaderData::availableList, PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, CreatePredXact(), PredXactListData::element, RWConflictPoolHeaderData::element, HASHCTL::entrysize, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, 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, InvalidTransactionId, HASHCTL::keysize, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, PredXactListElementData::link, max_prepared_xacts, MaxBackends, MemSet, mul_size(), NPREDICATELOCKTARGETENTS, NULL, HASHCTL::num_partitions, NUM_PREDICATELOCK_PARTITIONS, PredXactListData::OldCommittedSxact, OldSerXidInit(), SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, predicatelock_hash(), PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, PredXactListDataSize, PredXactListElementDataSize, SERIALIZABLEXACT::prepareSeqNo, RWConflictDataSize, RWConflictPoolHeaderDataSize, ScratchTargetTagHash, SERIALIZABLEXACT::SeqNo, SetInvalidVirtualTransactionId, ShmemAlloc(), ShmemInitHash(), ShmemInitStruct(), SHMQueueInit(), SHMQueueInsertBefore(), SXACT_FLAG_COMMITTED, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SERIALIZABLEXACT::topXid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, and SERIALIZABLEXACT::xmin.

Referenced by CreateSharedMemoryAndSemaphores().

1098 {
1099  HASHCTL info;
1100  long max_table_size;
1101  Size requestSize;
1102  bool found;
1103 
1104  /*
1105  * Compute size of predicate lock target hashtable. Note these
1106  * calculations must agree with PredicateLockShmemSize!
1107  */
1108  max_table_size = NPREDICATELOCKTARGETENTS();
1109 
1110  /*
1111  * Allocate hash table for PREDICATELOCKTARGET structs. This stores
1112  * per-predicate-lock-target information.
1113  */
1114  MemSet(&info, 0, sizeof(info));
1115  info.keysize = sizeof(PREDICATELOCKTARGETTAG);
1116  info.entrysize = sizeof(PREDICATELOCKTARGET);
1118 
1119  PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
1120  max_table_size,
1121  max_table_size,
1122  &info,
1123  HASH_ELEM | HASH_BLOBS |
1125 
1126  /* Assume an average of 2 xacts per target */
1127  max_table_size *= 2;
1128 
1129  /*
1130  * Reserve a dummy entry in the hash table; we use it to make sure there's
1131  * always one entry available when we need to split or combine a page,
1132  * because running out of space there could mean aborting a
1133  * non-serializable transaction.
1134  */
1136 
1137  /*
1138  * Allocate hash table for PREDICATELOCK structs. This stores per
1139  * xact-lock-of-a-target information.
1140  */
1141  MemSet(&info, 0, sizeof(info));
1142  info.keysize = sizeof(PREDICATELOCKTAG);
1143  info.entrysize = sizeof(PREDICATELOCK);
1144  info.hash = predicatelock_hash;
1146 
1147  PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
1148  max_table_size,
1149  max_table_size,
1150  &info,
1153 
1154  /*
1155  * Compute size for serializable transaction hashtable. Note these
1156  * calculations must agree with PredicateLockShmemSize!
1157  */
1158  max_table_size = (MaxBackends + max_prepared_xacts);
1159 
1160  /*
1161  * Allocate a list to hold information on transactions participating in
1162  * predicate locking.
1163  *
1164  * Assume an average of 10 predicate locking transactions per backend.
1165  * This allows aggressive cleanup while detail is present before data must
1166  * be summarized for storage in SLRU and the "dummy" transaction.
1167  */
1168  max_table_size *= 10;
1169 
1170  PredXact = ShmemInitStruct("PredXactList",
1172  &found);
1173  if (!found)
1174  {
1175  int i;
1176 
1185  requestSize = mul_size((Size) max_table_size,
1187  PredXact->element = ShmemAlloc(requestSize);
1188  /* Add all elements to available list, clean. */
1189  memset(PredXact->element, 0, requestSize);
1190  for (i = 0; i < max_table_size; i++)
1191  {
1193  &(PredXact->element[i].link));
1194  }
1210  }
1211  /* This never changes, so let's keep a local copy. */
1213 
1214  /*
1215  * Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
1216  * information for serializable transactions which have accessed data.
1217  */
1218  MemSet(&info, 0, sizeof(info));
1219  info.keysize = sizeof(SERIALIZABLEXIDTAG);
1220  info.entrysize = sizeof(SERIALIZABLEXID);
1221 
1222  SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
1223  max_table_size,
1224  max_table_size,
1225  &info,
1226  HASH_ELEM | HASH_BLOBS |
1227  HASH_FIXED_SIZE);
1228 
1229  /*
1230  * Allocate space for tracking rw-conflicts in lists attached to the
1231  * transactions.
1232  *
1233  * Assume an average of 5 conflicts per transaction. Calculations suggest
1234  * that this will prevent resource exhaustion in even the most pessimal
1235  * loads up to max_connections = 200 with all 200 connections pounding the
1236  * database with serializable transactions. Beyond that, there may be
1237  * occasional transactions canceled when trying to flag conflicts. That's
1238  * probably OK.
1239  */
1240  max_table_size *= 5;
1241 
1242  RWConflictPool = ShmemInitStruct("RWConflictPool",
1244  &found);
1245  if (!found)
1246  {
1247  int i;
1248 
1250  requestSize = mul_size((Size) max_table_size,
1252  RWConflictPool->element = ShmemAlloc(requestSize);
1253  /* Add all elements to available list, clean. */
1254  memset(RWConflictPool->element, 0, requestSize);
1255  for (i = 0; i < max_table_size; i++)
1256  {
1258  &(RWConflictPool->element[i].outLink));
1259  }
1260  }
1261 
1262  /*
1263  * Create or attach to the header for the list of finished serializable
1264  * transactions.
1265  */
1267  ShmemInitStruct("FinishedSerializableTransactions",
1268  sizeof(SHM_QUEUE),
1269  &found);
1270  if (!found)
1272 
1273  /*
1274  * Initialize the SLRU storage for old committed serializable
1275  * transactions.
1276  */
1277  OldSerXidInit();
1278 
1279  /* Pre-calculate the hash and partition lock of the scratch entry */
1282 }
TransactionId finishedBefore
#define PredXactListDataSize
struct SERIALIZABLEXID SERIALIZABLEXID
static HTAB * PredicateLockTargetHash
Definition: predicate.c:380
#define HASH_ELEM
Definition: hsearch.h:87
#define NPREDICATELOCKTARGETENTS()
Definition: predicate.c:251
static PredXactList PredXact
Definition: predicate.c:367
TransactionId SxactGlobalXmin
struct SERIALIZABLEXIDTAG SERIALIZABLEXIDTAG
struct PREDICATELOCKTARGET PREDICATELOCKTARGET
Size entrysize
Definition: hsearch.h:73
static uint32 predicatelock_hash(const void *key, Size keysize)
Definition: predicate.c:1350
static HTAB * SerializableXidHash
Definition: predicate.c:379
#define MemSet(start, val, len)
Definition: c.h:853
static void OldSerXidInit(void)
Definition: predicate.c:790
void * ShmemAlloc(Size size)
Definition: shmem.c:157
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
#define SXACT_FLAG_COMMITTED
#define FirstNormalSerCommitSeqNo
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
#define HASH_PARTITION
Definition: hsearch.h:83
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:245
SHM_QUEUE possibleUnsafeConflicts
static HTAB * PredicateLockHash
Definition: predicate.c:381
int max_prepared_xacts
Definition: twophase.c:98
static RWConflictPoolHeader RWConflictPool
Definition: predicate.c:373
union SERIALIZABLEXACT::@56 SeqNo
struct PREDICATELOCK PREDICATELOCK
long num_partitions
Definition: hsearch.h:67
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
struct PREDICATELOCKTAG PREDICATELOCKTAG
int MaxBackends
Definition: globals.c:126
#define RWConflictDataSize
VirtualTransactionId vxid
#define InvalidTransactionId
Definition: transam.h:31
SerCommitSeqNo lastCommitBeforeSnapshot
SerCommitSeqNo commitSeqNo
#define RWConflictPoolHeaderDataSize
SerCommitSeqNo HavePartialClearedThrough
#define HASH_BLOBS
Definition: hsearch.h:88
Size mul_size(Size s1, Size s2)
Definition: shmem.c:492
SerCommitSeqNo CanPartialClearThrough
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:289
Size keysize
Definition: hsearch.h:72
#define NULL
Definition: c.h:226
#define SetInvalidVirtualTransactionId(vxid)
Definition: lock.h:78
struct PREDICATELOCKTARGETTAG PREDICATELOCKTARGETTAG
SerCommitSeqNo prepareSeqNo
size_t Size
Definition: c.h:353
SerCommitSeqNo LastSxactCommitSeqNo
SERIALIZABLEXACT * OldCommittedSxact
#define HASH_FIXED_SIZE
Definition: hsearch.h:96
static SERIALIZABLEXACT * OldCommittedSxact
Definition: predicate.c:352
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
int i
static const PREDICATELOCKTARGETTAG ScratchTargetTag
Definition: predicate.c:389
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:317
static SHM_QUEUE * FinishedSerializableTransactions
Definition: predicate.c:382
static uint32 ScratchTargetTagHash
Definition: predicate.c:390
static LWLock * ScratchPartitionLock
Definition: predicate.c:391
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:556
PredXactListElement element
#define PredXactListElementDataSize
HashValueFunc hash
Definition: hsearch.h:74
#define HASH_FUNCTION
Definition: hsearch.h:89
#define NUM_PREDICATELOCK_PARTITIONS
Definition: lwlock.h:121
static SERIALIZABLEXACT * NextPredXact ( SERIALIZABLEXACT sxact)
static

Definition at line 603 of file predicate.c.

References PredXactListData::activeList, Assert, PredXactListElementData::link, NULL, offsetof, ShmemAddrIsValid(), SHMQueueNext(), and PredXactListElementData::sxact.

Referenced by GetSerializableTransactionSnapshotInt(), and SetNewSxactGlobalXmin().

604 {
605  PredXactListElement ptle;
606 
607  Assert(ShmemAddrIsValid(sxact));
608 
609  ptle = (PredXactListElement)
610  (((char *) sxact)
613  ptle = (PredXactListElement)
615  &ptle->link,
617  if (!ptle)
618  return NULL;
619 
620  return &ptle->sxact;
621 }
static PredXactList PredXact
Definition: predicate.c:367
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
bool ShmemAddrIsValid(const void *addr)
Definition: shmem.c:263
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
struct PredXactListElementData * PredXactListElement
#define offsetof(type, field)
Definition: c.h:551
static void OldSerXidAdd ( TransactionId  xid,
SerCommitSeqNo  minConflictCommitSeqNo 
)
static

Definition at line 828 of file predicate.c.

References Assert, ereport, errhint(), errmsg(), FirstNormalTransactionId, OldSerXidControlData::headPage, OldSerXidControlData::headXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), OldSerXidNextPage, OldSerXidPage, OldSerXidPagePrecedesLogically(), OldSerXidSlruCtl, OldSerXidValue, SimpleLruReadPage(), SimpleLruZeroPage(), OldSerXidControlData::tailXid, TransactionIdFollows(), TransactionIdIsValid, TransactionIdPrecedes(), WARNING, and OldSerXidControlData::warningIssued.

Referenced by SummarizeOldestCommittedSxact().

829 {
830  TransactionId tailXid;
831  int targetPage;
832  int slotno;
833  int firstZeroPage;
834  bool isNewPage;
835 
837 
838  targetPage = OldSerXidPage(xid);
839 
840  LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);
841 
842  /*
843  * If no serializable transactions are active, there shouldn't be anything
844  * to push out to the SLRU. Hitting this assert would mean there's
845  * something wrong with the earlier cleanup logic.
846  */
847  tailXid = oldSerXidControl->tailXid;
848  Assert(TransactionIdIsValid(tailXid));
849 
850  /*
851  * If the SLRU is currently unused, zero out the whole active region from
852  * tailXid to headXid before taking it into use. Otherwise zero out only
853  * any new pages that enter the tailXid-headXid range as we advance
854  * headXid.
855  */
856  if (oldSerXidControl->headPage < 0)
857  {
858  firstZeroPage = OldSerXidPage(tailXid);
859  isNewPage = true;
860  }
861  else
862  {
863  firstZeroPage = OldSerXidNextPage(oldSerXidControl->headPage);
865  targetPage);
866  }
867 
870  oldSerXidControl->headXid = xid;
871  if (isNewPage)
872  oldSerXidControl->headPage = targetPage;
873 
874  /*
875  * Give a warning if we're about to run out of SLRU pages.
876  *
877  * slru.c has a maximum of 64k segments, with 32 (SLRU_PAGES_PER_SEGMENT)
878  * pages each. We need to store a 64-bit integer for each Xid, and with
879  * default 8k block size, 65536*32 pages is only enough to cover 2^30
880  * XIDs. If we're about to hit that limit and wrap around, warn the user.
881  *
882  * To avoid spamming the user, we only give one warning when we've used 1
883  * billion XIDs, and stay silent until the situation is fixed and the
884  * number of XIDs used falls below 800 million again.
885  *
886  * XXX: We have no safeguard to actually *prevent* the wrap-around,
887  * though. All you get is a warning.
888  */
890  {
891  TransactionId lowWatermark;
892 
893  lowWatermark = tailXid + 800000000;
894  if (lowWatermark < FirstNormalTransactionId)
895  lowWatermark = FirstNormalTransactionId;
896  if (TransactionIdPrecedes(xid, lowWatermark))
898  }
899  else
900  {
901  TransactionId highWatermark;
902 
903  highWatermark = tailXid + 1000000000;
904  if (highWatermark < FirstNormalTransactionId)
905  highWatermark = FirstNormalTransactionId;
906  if (TransactionIdFollows(xid, highWatermark))
907  {
910  (errmsg("memory for serializable conflict tracking is nearly exhausted"),
911  errhint("There might be an idle transaction or a forgotten prepared transaction causing this.")));
912  }
913  }
914 
915  if (isNewPage)
916  {
917  /* Initialize intervening pages. */
918  while (firstZeroPage != targetPage)
919  {
920  (void) SimpleLruZeroPage(OldSerXidSlruCtl, firstZeroPage);
921  firstZeroPage = OldSerXidNextPage(firstZeroPage);
922  }
923  slotno = SimpleLruZeroPage(OldSerXidSlruCtl, targetPage);
924  }
925  else
926  slotno = SimpleLruReadPage(OldSerXidSlruCtl, targetPage, true, xid);
927 
928  OldSerXidValue(slotno, xid) = minConflictCommitSeqNo;
929  OldSerXidSlruCtl->shared->page_dirty[slotno] = true;
930 
931  LWLockRelease(OldSerXidLock);
932 }
int errhint(const char *fmt,...)
Definition: elog.c:987
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:394
#define OldSerXidPage(xid)
Definition: predicate.c:331
#define OldSerXidSlruCtl
Definition: predicate.c:312
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define FirstNormalTransactionId
Definition: transam.h:34
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:370
TransactionId headXid
Definition: predicate.c:337
#define ereport(elevel, rest)
Definition: elog.h:122
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define WARNING
Definition: elog.h:40
#define Assert(condition)
Definition: c.h:671
static bool OldSerXidPagePrecedesLogically(int p, int q)
Definition: predicate.c:767
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
static OldSerXidControl oldSerXidControl
Definition: predicate.c:344
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define OldSerXidValue(slotno, xid)
Definition: predicate.c:327
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:258
#define OldSerXidNextPage(page)
Definition: predicate.c:325
TransactionId tailXid
Definition: predicate.c:338
static SerCommitSeqNo OldSerXidGetMinConflictCommitSeqNo ( TransactionId  xid)
static

Definition at line 940 of file predicate.c.

References Assert, OldSerXidControlData::headXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), OldSerXidPage, OldSerXidSlruCtl, OldSerXidValue, SimpleLruReadPage_ReadOnly(), OldSerXidControlData::tailXid, TransactionIdFollows(), TransactionIdIsValid, TransactionIdPrecedes(), and val.

Referenced by CheckForSerializableConflictOut().

941 {
942  TransactionId headXid;
943  TransactionId tailXid;
945  int slotno;
946 
948 
949  LWLockAcquire(OldSerXidLock, LW_SHARED);
950  headXid = oldSerXidControl->headXid;
951  tailXid = oldSerXidControl->tailXid;
952  LWLockRelease(OldSerXidLock);
953 
954  if (!TransactionIdIsValid(headXid))
955  return 0;
956 
957  Assert(TransactionIdIsValid(tailXid));
958 
959  if (TransactionIdPrecedes(xid, tailXid)
960  || TransactionIdFollows(xid, headXid))
961  return 0;
962 
963  /*
964  * The following function must be called without holding OldSerXidLock,
965  * but will return with that lock held, which must then be released.
966  */
968  OldSerXidPage(xid), xid);
969  val = OldSerXidValue(slotno, xid);
970  LWLockRelease(OldSerXidLock);
971  return val;
972 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:394
#define OldSerXidPage(xid)
Definition: predicate.c:331
#define OldSerXidSlruCtl
Definition: predicate.c:312
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
TransactionId headXid
Definition: predicate.c:337
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:462
uint64 SerCommitSeqNo
#define Assert(condition)
Definition: c.h:671
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
static OldSerXidControl oldSerXidControl
Definition: predicate.c:344
#define OldSerXidValue(slotno, xid)
Definition: predicate.c:327
#define TransactionIdIsValid(xid)
Definition: transam.h:41
long val
Definition: informix.c:689
TransactionId tailXid
Definition: predicate.c:338
static void OldSerXidInit ( void  )
static

Definition at line 790 of file predicate.c.

References OldSerXidControlData::headPage, OldSerXidControlData::headXid, InvalidTransactionId, LWTRANCHE_OLDSERXID_BUFFERS, NUM_OLDSERXID_BUFFERS, OldSerXidPagePrecedesLogically(), OldSerXidSlruCtl, ShmemInitStruct(), SimpleLruInit(), OldSerXidControlData::tailXid, and OldSerXidControlData::warningIssued.

Referenced by InitPredicateLocks().

791 {
792  bool found;
793 
794  /*
795  * Set up SLRU management of the pg_serial data.
796  */
798  SimpleLruInit(OldSerXidSlruCtl, "oldserxid",
799  NUM_OLDSERXID_BUFFERS, 0, OldSerXidLock, "pg_serial",
801  /* Override default assumption that writes should be fsync'd */
802  OldSerXidSlruCtl->do_fsync = false;
803 
804  /*
805  * Create or attach to the OldSerXidControl structure.
806  */
808  ShmemInitStruct("OldSerXidControlData", sizeof(OldSerXidControlData), &found);
809 
810  if (!found)
811  {
812  /*
813  * Set control information to reflect empty SLRU.
814  */
819  }
820 }
struct OldSerXidControlData * OldSerXidControl
Definition: predicate.c:342
#define NUM_OLDSERXID_BUFFERS
Definition: predicate.h:28
#define OldSerXidSlruCtl
Definition: predicate.c:312
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
#define InvalidTransactionId
Definition: transam.h:31
TransactionId headXid
Definition: predicate.c:337
static bool OldSerXidPagePrecedesLogically(int p, int q)
Definition: predicate.c:767
static OldSerXidControl oldSerXidControl
Definition: predicate.c:344
TransactionId tailXid
Definition: predicate.c:338
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id)
Definition: slru.c:164
static bool OldSerXidPagePrecedesLogically ( int  p,
int  q 
)
static

Definition at line 767 of file predicate.c.

References Assert, and OLDSERXID_MAX_PAGE.

Referenced by OldSerXidAdd(), and OldSerXidInit().

768 {
769  int diff;
770 
771  /*
772  * We have to compare modulo (OLDSERXID_MAX_PAGE+1)/2. Both inputs should
773  * be in the range 0..OLDSERXID_MAX_PAGE.
774  */
775  Assert(p >= 0 && p <= OLDSERXID_MAX_PAGE);
776  Assert(q >= 0 && q <= OLDSERXID_MAX_PAGE);
777 
778  diff = p - q;
779  if (diff >= ((OLDSERXID_MAX_PAGE + 1) / 2))
780  diff -= OLDSERXID_MAX_PAGE + 1;
781  else if (diff < -((int) (OLDSERXID_MAX_PAGE + 1) / 2))
782  diff += OLDSERXID_MAX_PAGE + 1;
783  return diff < 0;
784 }
#define OLDSERXID_MAX_PAGE
Definition: predicate.c:322
#define Assert(condition)
Definition: c.h:671
static void OldSerXidSetActiveSerXmin ( TransactionId  xid)
static

Definition at line 981 of file predicate.c.

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

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

982 {
983  LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);
984 
985  /*
986  * When no sxacts are active, nothing overlaps, set the xid values to
987  * invalid to show that there are no valid entries. Don't clear headPage,
988  * though. A new xmin might still land on that page, and we don't want to
989  * repeatedly zero out the same page.
990  */
991  if (!TransactionIdIsValid(xid))
992  {
995  LWLockRelease(OldSerXidLock);
996  return;
997  }
998 
999  /*
1000  * When we're recovering prepared transactions, the global xmin might move
1001  * backwards depending on the order they're recovered. Normally that's not
1002  * OK, but during recovery no serializable transactions will commit, so
1003  * the SLRU is empty and we can get away with it.
1004  */
1005  if (RecoveryInProgress())
1006  {
1010  {
1011  oldSerXidControl->tailXid = xid;
1012  }
1013  LWLockRelease(OldSerXidLock);
1014  return;
1015  }
1016 
1019 
1020  oldSerXidControl->tailXid = xid;
1021 
1022  LWLockRelease(OldSerXidLock);
1023 }
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
bool RecoveryInProgress(void)
Definition: xlog.c:7805
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define InvalidTransactionId
Definition: transam.h:31
TransactionId headXid
Definition: predicate.c:337
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define Assert(condition)
Definition: c.h:671
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
static OldSerXidControl oldSerXidControl
Definition: predicate.c:344
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId tailXid
Definition: predicate.c:338
static void OnConflict_CheckForSerializationFailure ( const SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
)
static

Definition at line 4454 of file predicate.c.

References Assert, SERIALIZABLEXACT::commitSeqNo, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LWLockHeldByMe(), LWLockRelease(), NULL, offsetof, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::prepareSeqNo, SERIALIZABLEXACT::SeqNo, SHMQueueNext(), SXACT_FLAG_DOOMED, SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, RWConflictData::sxactIn, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, RWConflictData::sxactOut, and SERIALIZABLEXACT::topXid.

Referenced by FlagRWConflict().

4456 {
4457  bool failure;
4458  RWConflict conflict;
4459 
4460  Assert(LWLockHeldByMe(SerializableXactHashLock));
4461 
4462  failure = false;
4463 
4464  /*------------------------------------------------------------------------
4465  * Check for already-committed writer with rw-conflict out flagged
4466  * (conflict-flag on W means that T2 committed before W):
4467  *
4468  * R ------> W ------> T2
4469  * rw rw
4470  *
4471  * That is a dangerous structure, so we must abort. (Since the writer
4472  * has already committed, we must be the reader)
4473  *------------------------------------------------------------------------
4474  */
4475  if (SxactIsCommitted(writer)
4476  && (SxactHasConflictOut(writer) || SxactHasSummaryConflictOut(writer)))
4477  failure = true;
4478 
4479  /*------------------------------------------------------------------------
4480  * Check whether the writer has become a pivot with an out-conflict
4481  * committed transaction (T2), and T2 committed first:
4482  *
4483  * R ------> W ------> T2
4484  * rw rw
4485  *
4486  * Because T2 must've committed first, there is no anomaly if:
4487  * - the reader committed before T2
4488  * - the writer committed before T2
4489  * - the reader is a READ ONLY transaction and the reader was concurrent
4490  * with T2 (= reader acquired its snapshot before T2 committed)
4491  *
4492  * We also handle the case that T2 is prepared but not yet committed
4493  * here. In that case T2 has already checked for conflicts, so if it
4494  * commits first, making the above conflict real, it's too late for it
4495  * to abort.
4496  *------------------------------------------------------------------------
4497  */
4498  if (!failure)
4499  {
4500  if (SxactHasSummaryConflictOut(writer))
4501  {
4502  failure = true;
4503  conflict = NULL;
4504  }
4505  else
4506  conflict = (RWConflict)
4507  SHMQueueNext(&writer->outConflicts,
4508  &writer->outConflicts,
4509  offsetof(RWConflictData, outLink));
4510  while (conflict)
4511  {
4512  SERIALIZABLEXACT *t2 = conflict->sxactIn;
4513 
4514  if (SxactIsPrepared(t2)
4515  && (!SxactIsCommitted(reader)
4516  || t2->prepareSeqNo <= reader->commitSeqNo)
4517  && (!SxactIsCommitted(writer)
4518  || t2->prepareSeqNo <= writer->commitSeqNo)
4519  && (!SxactIsReadOnly(reader)
4520  || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
4521  {
4522  failure = true;
4523  break;
4524  }
4525  conflict = (RWConflict)
4526  SHMQueueNext(&writer->outConflicts,
4527  &conflict->outLink,
4528  offsetof(RWConflictData, outLink));
4529  }
4530  }
4531 
4532  /*------------------------------------------------------------------------
4533  * Check whether the reader has become a pivot with a writer
4534  * that's committed (or prepared):
4535  *
4536  * T0 ------> R ------> W
4537  * rw rw
4538  *
4539  * Because W must've committed first for an anomaly to occur, there is no
4540  * anomaly if:
4541  * - T0 committed before the writer
4542  * - T0 is READ ONLY, and overlaps the writer
4543  *------------------------------------------------------------------------
4544  */
4545  if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
4546  {
4547  if (SxactHasSummaryConflictIn(reader))
4548  {
4549  failure = true;
4550  conflict = NULL;
4551  }
4552  else
4553  conflict = (RWConflict)
4554  SHMQueueNext(&reader->inConflicts,
4555  &reader->inConflicts,
4556  offsetof(RWConflictData, inLink));
4557  while (conflict)
4558  {
4559  SERIALIZABLEXACT *t0 = conflict->sxactOut;
4560 
4561  if (!SxactIsDoomed(t0)
4562  && (!SxactIsCommitted(t0)
4563  || t0->commitSeqNo >= writer->prepareSeqNo)
4564  && (!SxactIsReadOnly(t0)
4565  || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
4566  {
4567  failure = true;
4568  break;
4569  }
4570  conflict = (RWConflict)
4571  SHMQueueNext(&reader->inConflicts,
4572  &conflict->inLink,
4573  offsetof(RWConflictData, inLink));
4574  }
4575  }
4576 
4577  if (failure)
4578  {
4579  /*
4580  * We have to kill a transaction to avoid a possible anomaly from
4581  * occurring. If the writer is us, we can just ereport() to cause a
4582  * transaction abort. Otherwise we flag the writer for termination,
4583  * causing it to abort when it tries to commit. However, if the writer
4584  * is a prepared transaction, already prepared, we can't abort it
4585  * anymore, so we have to kill the reader instead.
4586  */
4587  if (MySerializableXact == writer)
4588  {
4589  LWLockRelease(SerializableXactHashLock);
4590  ereport(ERROR,
4591  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4592  errmsg("could not serialize access due to read/write dependencies among transactions"),
4593  errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
4594  errhint("The transaction might succeed if retried.")));
4595  }
4596  else if (SxactIsPrepared(writer))
4597  {
4598  LWLockRelease(SerializableXactHashLock);
4599 
4600  /* if we're not the writer, we have to be the reader */
4601  Assert(MySerializableXact == reader);
4602  ereport(ERROR,
4603  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4604  errmsg("could not serialize access due to read/write dependencies among transactions"),
4605  errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
4606  errhint("The transaction might succeed if retried.")));
4607  }
4608  writer->flags |= SXACT_FLAG_DOOMED;
4609  }
4610 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:268
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:404
int errhint(const char *fmt,...)
Definition: elog.c:987
#define SxactHasSummaryConflictIn(sxact)
Definition: predicate.c:269
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1830
struct RWConflictData * RWConflict
int errcode(int sqlerrcode)
Definition: elog.c:575
#define SxactIsPrepared(sxact)
Definition: predicate.c:265
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
SERIALIZABLEXACT * sxactIn
#define SxactIsDoomed(sxact)
Definition: predicate.c:267
#define ERROR
Definition: elog.h:43
union SERIALIZABLEXACT::@56 SeqNo
SerCommitSeqNo lastCommitBeforeSnapshot
#define ereport(elevel, rest)
Definition: elog.h:122
#define SxactHasSummaryConflictOut(sxact)
Definition: predicate.c:270
SerCommitSeqNo commitSeqNo
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define SXACT_FLAG_DOOMED
#define SxactHasConflictOut(sxact)
Definition: predicate.c:276
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
SerCommitSeqNo prepareSeqNo
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define SxactIsCommitted(sxact)
Definition: predicate.c:264
#define offsetof(type, field)
Definition: c.h:551
SERIALIZABLEXACT * sxactOut
bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)

Definition at line 1853 of file predicate.c.

References RelFileNode::dbNode, HASH_FIND, hash_search_with_hash_value(), LW_SHARED, LWLockAcquire(), LWLockRelease(), NULL, PredicateLockHashPartitionLock, PredicateLockTargetTagHashCode, RelationData::rd_id, RelationData::rd_node, and SET_PREDICATELOCKTARGETTAG_PAGE.

1854 {
1855  PREDICATELOCKTARGETTAG targettag;
1856  uint32 targettaghash;
1857  LWLock *partitionLock;
1858  PREDICATELOCKTARGET *target;
1859 
1861  relation->rd_node.dbNode,
1862  relation->rd_id,
1863  blkno);
1864 
1865  targettaghash = PredicateLockTargetTagHashCode(&targettag);
1866  partitionLock = PredicateLockHashPartitionLock(targettaghash);
1867  LWLockAcquire(partitionLock, LW_SHARED);
1868  target = (PREDICATELOCKTARGET *)
1870  &targettag, targettaghash,
1871  HASH_FIND, NULL);
1872  LWLockRelease(partitionLock);
1873 
1874  return (target != NULL);
1875 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:898
Definition: lwlock.h:32
static HTAB * PredicateLockTargetHash
Definition: predicate.c:380
#define SET_PREDICATELOCKTARGETTAG_PAGE(locktag, dboid, reloid, blocknum)
#define PredicateLockHashPartitionLock(hashcode)
Definition: predicate.c:245
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
unsigned int uint32
Definition: c.h:265
Oid rd_id
Definition: rel.h:115
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:289
RelFileNode rd_node
Definition: rel.h:85
#define NULL
Definition: c.h:226
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
void PostPrepare_PredicateLocks ( TransactionId  xid)

Definition at line 4791 of file predicate.c.

References Assert, hash_destroy(), InvalidSerializableXact, MyXactDidWrite, NULL, SERIALIZABLEXACT::pid, and SxactIsPrepared.

Referenced by PrepareTransaction().

4792 {
4794  return;
4795 
4797 
4798  MySerializableXact->pid = 0;
4799 
4802 
4804  MyXactDidWrite = false;
4805 }
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:404
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:793
#define SxactIsPrepared(sxact)
Definition: predicate.c:265
#define InvalidSerializableXact
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
static HTAB * LocalPredicateLockHash
Definition: predicate.c:397
static bool MyXactDidWrite
Definition: predicate.c:405
void PreCommit_CheckForSerializationFailure ( void  )

Definition at line 4629 of file predicate.c.

References Assert, ereport, errcode(), errdetail_internal(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, InvalidSerializableXact, IsolationIsSerializable, PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), offsetof, SERIALIZABLEXACT::prepareSeqNo, SHMQueueNext(), SXACT_FLAG_DOOMED, SXACT_FLAG_PREPARED, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, and RWConflictData::sxactOut.

Referenced by CommitTransaction(), and PrepareTransaction().

4630 {
4631  RWConflict nearConflict;
4632 
4634  return;
4635 
4637 
4638  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4639 
4640  /* Check if someone else has already decided that we need to die */
4642  {
4643  LWLockRelease(SerializableXactHashLock);
4644  ereport(ERROR,
4645  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4646  errmsg("could not serialize access due to read/write dependencies among transactions"),
4647  errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
4648  errhint("The transaction might succeed if retried.")));
4649  }
4650 
4651  nearConflict = (RWConflict)
4654  offsetof(RWConflictData, inLink));
4655  while (nearConflict)
4656  {
4657  if (!SxactIsCommitted(nearConflict->sxactOut)
4658  && !SxactIsDoomed(nearConflict->sxactOut))
4659  {
4660  RWConflict farConflict;
4661 
4662  farConflict = (RWConflict)
4663  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4664  &nearConflict->sxactOut->inConflicts,
4665  offsetof(RWConflictData, inLink));
4666  while (farConflict)
4667  {
4668  if (farConflict->sxactOut == MySerializableXact
4669  || (!SxactIsCommitted(farConflict->sxactOut)
4670  && !SxactIsReadOnly(farConflict->sxactOut)
4671  && !SxactIsDoomed(farConflict->sxactOut)))
4672  {
4673  /*
4674  * Normally, we kill the pivot transaction to make sure we
4675  * make progress if the failing transaction is retried.
4676  * However, we can't kill it if it's already prepared, so
4677  * in that case we commit suicide instead.
4678  */
4679  if (SxactIsPrepared(nearConflict->sxactOut))
4680  {
4681  LWLockRelease(SerializableXactHashLock);
4682  ereport(ERROR,
4683  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4684  errmsg("could not serialize access due to read/write dependencies among transactions"),
4685  errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
4686  errhint("The transaction might succeed if retried.")));
4687  }
4688  nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
4689  break;
4690  }
4691  farConflict = (RWConflict)
4692  SHMQueueNext(&nearConflict->sxactOut->inConflicts,
4693  &farConflict->inLink,
4694  offsetof(RWConflictData, inLink));
4695  }
4696  }
4697 
4698  nearConflict = (RWConflict)
4700  &nearConflict->inLink,
4701  offsetof(RWConflictData, inLink));
4702  }
4703 
4706 
4707  LWLockRelease(SerializableXactHashLock);
4708 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:268
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:404
int errhint(const char *fmt,...)
Definition: elog.c:987
static PredXactList PredXact
Definition: predicate.c:367
struct RWConflictData * RWConflict
int errcode(int sqlerrcode)
Definition: elog.c:575
#define SxactIsPrepared(sxact)
Definition: predicate.c:265
int errdetail_internal(const char *fmt,...)
Definition: elog.c:900
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define SxactIsDoomed(sxact)
Definition: predicate.c:267
#define ERROR
Definition: elog.h:43
#define InvalidSerializableXact
#define SXACT_FLAG_PREPARED
#define ereport(elevel, rest)
Definition: elog.h:122
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define SXACT_FLAG_DOOMED
#define Assert(condition)
Definition: c.h:671
SerCommitSeqNo prepareSeqNo
SerCommitSeqNo LastSxactCommitSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define IsolationIsSerializable()
Definition: xact.h:44
#define SxactIsCommitted(sxact)
Definition: predicate.c:264
#define offsetof(type, field)
Definition: c.h:551
SERIALIZABLEXACT * sxactOut
static uint32 predicatelock_hash ( const void *  key,
Size  keysize 
)
static

Definition at line 1350 of file predicate.c.

References Assert, PREDICATELOCKTAG::myTarget, PredicateLockHashCodeFromTargetHashCode, PredicateLockTargetTagHashCode, and PREDICATELOCKTARGET::tag.

Referenced by InitPredicateLocks().

1351 {
1352  const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
1353  uint32 targethash;
1354 
1355  Assert(keysize == sizeof(PREDICATELOCKTAG));
1356 
1357  /* Look into the associated target object, and compute its hash code */
1358  targethash = PredicateLockTargetTagHashCode(&predicatelocktag->myTarget->tag);
1359 
1360  return PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash);
1361 }
#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash)
Definition: predicate.c:302
unsigned int uint32
Definition: c.h:265
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:289
PREDICATELOCKTARGETTAG tag
#define Assert(condition)
Definition: c.h:671
PREDICATELOCKTARGET * myTarget
void predicatelock_twophase_recover ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 4840 of file predicate.c.

References Assert, VirtualTransactionId::backendId, SERIALIZABLEXACT::commitSeqNo, CreatePredicateLock(), CreatePredXact(), TwoPhasePredicateRecord::data, ereport, errcode(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, SERIALIZABLEXACT::flags, TwoPhasePredicateXactRecord::flags, HASH_ENTER, HASH_FIND, hash_search(), SERIALIZABLEXACT::inConflicts, InvalidBackendId, InvalidSerCommitSeqNo, InvalidSerializableXact, InvalidTransactionId, SERIALIZABLEXACT::lastCommitBeforeSnapshot, VirtualTransactionId::localTransactionId, TwoPhasePredicateRecord::lockRecord, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_prepared_xacts, MaxBackends, SERIALIZABLEXID::myXact, NULL, OldSerXidSetActiveSerXmin(), SERIALIZABLEXACT::outConflicts, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, SERIALIZABLEXACT::prepareSeqNo, RecoverySerCommitSeqNo, SERIALIZABLEXACT::SeqNo, SHMQueueElemInit(), SHMQueueInit(), 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.

4842 {
4843  TwoPhasePredicateRecord *record;
4844 
4845  Assert(len == sizeof(TwoPhasePredicateRecord));
4846 
4847  record = (TwoPhasePredicateRecord *) recdata;
4848 
4849  Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
4850  (record->type == TWOPHASEPREDICATERECORD_LOCK));
4851 
4852  if (record->type == TWOPHASEPREDICATERECORD_XACT)
4853  {
4854  /* Per-transaction record. Set up a SERIALIZABLEXACT. */
4855  TwoPhasePredicateXactRecord *xactRecord;
4856  SERIALIZABLEXACT *sxact;
4857  SERIALIZABLEXID *sxid;
4858  SERIALIZABLEXIDTAG sxidtag;
4859  bool found;
4860 
4861  xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;
4862 
4863  LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
4864  sxact = CreatePredXact();
4865  if (!sxact)
4866  ereport(ERROR,
4867  (errcode(ERRCODE_OUT_OF_MEMORY),
4868  errmsg("out of shared memory")));
4869 
4870  /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
4871  sxact->vxid.backendId = InvalidBackendId;
4873  sxact->pid = 0;
4874 
4875  /* a prepared xact hasn't committed yet */
4879 
4881 
4882  /*
4883  * Don't need to track this; no transactions running at the time the
4884  * recovered xact started are still active, except possibly other
4885  * prepared xacts and we don't care whether those are RO_SAFE or not.
4886  */
4888 
4889  SHMQueueInit(&(sxact->predicateLocks));
4890  SHMQueueElemInit(&(sxact->finishedLink));
4891 
4892  sxact->topXid = xid;
4893  sxact->xmin = xactRecord->xmin;
4894  sxact->flags = xactRecord->flags;
4895  Assert(SxactIsPrepared(sxact));
4896  if (!SxactIsReadOnly(sxact))
4897  {
4901  }
4902 
4903  /*
4904  * We don't know whether the transaction had any conflicts or not, so
4905  * we'll conservatively assume that it had both a conflict in and a
4906  * conflict out, and represent that with the summary conflict flags.
4907  */
4908  SHMQueueInit(&(sxact->outConflicts));
4909  SHMQueueInit(&(sxact->inConflicts));
4912 
4913  /* Register the transaction's xid */
4914  sxidtag.xid = xid;
4916  &sxidtag,
4917  HASH_ENTER, &found);
4918  Assert(sxid != NULL);
4919  Assert(!found);
4920  sxid->myXact = (SERIALIZABLEXACT *) sxact;
4921 
4922  /*
4923  * Update global xmin. Note that this is a special case compared to
4924  * registering a normal transaction, because the global xmin might go
4925  * backwards. That's OK, because until recovery is over we're not
4926  * going to complete any transactions or create any non-prepared
4927  * transactions, so there's no danger of throwing away.
4928  */
4931  {
4932  PredXact->SxactGlobalXmin = sxact->xmin;
4935  }
4936  else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
4937  {
4940  }
4941 
4942  LWLockRelease(SerializableXactHashLock);
4943  }
4944  else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
4945  {
4946  /* Lock record. Recreate the PREDICATELOCK */
4947  TwoPhasePredicateLockRecord *lockRecord;
4948  SERIALIZABLEXID *sxid;
4949  SERIALIZABLEXACT *sxact;
4950  SERIALIZABLEXIDTAG sxidtag;
4951  uint32 targettaghash;
4952 
4953  lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
4954  targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);
4955 
4956  LWLockAcquire(SerializableXactHashLock, LW_SHARED);
4957  sxidtag.xid = xid;
4958  sxid = (SERIALIZABLEXID *)
4960  LWLockRelease(SerializableXactHashLock);
4961 
4962  Assert(sxid != NULL);
4963  sxact = sxid->myXact;
4964  Assert(sxact != InvalidSerializableXact);
4965 
4966  CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
4967  }
4968 }
#define SxactIsReadOnly(sxact)
Definition: predicate.c:268
TransactionId finishedBefore
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2295
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
static PredXactList PredXact
Definition: predicate.c:367
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT
TransactionId SxactGlobalXmin
int errcode(int sqlerrcode)
Definition: elog.c:575
static HTAB * SerializableXidHash
Definition: predicate.c:379
SERIALIZABLEXACT * myXact
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
#define SxactIsPrepared(sxact)
Definition: predicate.c:265
TwoPhasePredicateRecordType type
LocalTransactionId localTransactionId
Definition: lock.h:66
union TwoPhasePredicateRecord::@57 data
PREDICATELOCKTARGETTAG target
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
SHM_QUEUE possibleUnsafeConflicts
#define ERROR
Definition: elog.h:43
int max_prepared_xacts
Definition: twophase.c:98
union SERIALIZABLEXACT::@56 SeqNo
TwoPhasePredicateXactRecord xactRecord
#define InvalidSerializableXact
int MaxBackends
Definition: globals.c:126
VirtualTransactionId vxid
#define InvalidTransactionId
Definition: transam.h:31
unsigned int uint32
Definition: c.h:265
uint32 LocalTransactionId
Definition: c.h:396
SerCommitSeqNo lastCommitBeforeSnapshot
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvalidSerCommitSeqNo
SerCommitSeqNo commitSeqNo
#define PredicateLockTargetTagHashCode(predicatelocktargettag)
Definition: predicate.c:289
#define InvalidBackendId
Definition: backendid.h:23
#define RecoverySerCommitSeqNo
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
BackendId backendId
Definition: lock.h:65
static void OldSerXidSetActiveSerXmin(TransactionId xid)
Definition: predicate.c:981
SerCommitSeqNo prepareSeqNo
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
void SHMQueueElemInit(SHM_QUEUE *queue)
Definition: shmqueue.c:57
int errmsg(const char *fmt,...)
Definition: elog.c:797
void SHMQueueInit(SHM_QUEUE *queue)
Definition: shmqueue.c:36
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TwoPhasePredicateLockRecord lockRecord
#define SXACT_FLAG_SUMMARY_CONFLICT_IN
static SERIALIZABLEXACT * CreatePredXact(void)
Definition: predicate.c:556
static void PredicateLockAcquire ( const PREDICATELOCKTARGETTAG targettag)
static

Definition at line 2356 of file predicate.c.

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

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

2357 {
2358  uint32 targettaghash;
2359  bool found;
2360  LOCALPREDICATELOCK *locallock;
2361 
2362  /* Do we have the lock already, or a covering lock? */
2363  if (PredicateLockExists(targettag))
2364  return;
2365 
2366  if (CoarserLockCovers(targettag))
2367  return;
2368 
2369  /* the same hash and LW lock apply to the lock target and the local lock. */
2370  targettaghash = PredicateLockTargetTagHashCode(targettag);
2371 
2372  /* Acquire lock in local table */
2373  locallock = (LOCALPREDICATELOCK *)
2375  targettag, targettaghash,
2376  HASH_ENTER, &found);
2377  locallock->held = true;
2378  if (!found)
2379  locallock->childLocks = 0;
2380 
2381  /* Actually create the lock */
2382  CreatePredicateLock(targettag, targettaghash, MySerializableXact);
2383 
2384  /*
2385  * Lock has been acquired. Check whether it should be promoted to a
2386  * coarser granularity, or whether there are finer-granularity locks to
2387  * clean up.
2388  */
2389  if (CheckAndPromotePredicateLockRequest(targettag))
2390  {
2391  /*
2392  * Lock request was promoted to a coarser-granularity lock, and that
2393  * lock was acquired. It will delete this lock and any of its
2394  * children, so we're done.
2395  */
2396  }
2397  else
2398  {
2399  /* Clean up any finer-granularity locks */
2401  DeleteChildTargetLocks(targettag);
2402  }
2403 }
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:898
static SERIALIZABLEXACT * MySerializableXact
Definition: predicate.c:404
static void CreatePredicateLock(const PREDICATELOCKTARGETTAG *targettag, uint32 targettaghash, SERIALIZABLEXACT *sxact)
Definition: predicate.c:2295
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *targettag)
Definition: predicate.c:1890
static void DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
Definition: predicate.c:2057
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
unsigned int uint32
Definition: c.h:265