Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Functions | Variables

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 "miscadmin.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

Defines

#define TargetTagIsCoveredBy(covered_target, covering_target)
#define PredicateLockHashPartition(hashcode)   ((hashcode) % NUM_PREDICATELOCK_PARTITIONS)
#define PredicateLockHashPartitionLock(hashcode)   ((LWLockId) (FirstPredicateLockMgrLock + PredicateLockHashPartition(hashcode)))
#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)   (tag_hash((predicatelocktargettag), sizeof(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, 0}
static uint32 ScratchTargetTagHash
static int ScratchPartitionLock
static HTABLocalPredicateLockHash = NULL
static SERIALIZABLEXACTMySerializableXact = InvalidSerializableXact
static bool MyXactDidWrite = false

Define Documentation

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

Definition at line 246 of file predicate.c.

Referenced by InitPredicateLocks(), and PredicateLockShmemSize().

#define OLDSERXID_ENTRIESPERPAGE   (OLDSERXID_PAGESIZE / OLDSERXID_ENTRYSIZE)

Definition at line 311 of file predicate.c.

#define OLDSERXID_ENTRYSIZE   sizeof(SerCommitSeqNo)

Definition at line 310 of file predicate.c.

#define OLDSERXID_MAX_PAGE
Value:

Definition at line 317 of file predicate.c.

Referenced by OldSerXidPagePrecedesLogically().

#define OLDSERXID_PAGESIZE   BLCKSZ

Definition at line 309 of file predicate.c.

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

Definition at line 320 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 327 of file predicate.c.

#define OldSerXidSlruCtl   (&OldSerXidSlruCtlData)
#define OldSerXidValue (   slotno,
  xid 
)
Value:
(*((SerCommitSeqNo *) \
    (OldSerXidSlruCtl->shared->page_buffer[slotno] + \
    ((((uint32) (xid)) % OLDSERXID_ENTRIESPERPAGE) * OLDSERXID_ENTRYSIZE))))

Definition at line 322 of file predicate.c.

Referenced by OldSerXidAdd(), and OldSerXidGetMinConflictCommitSeqNo().

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

Definition at line 241 of file predicate.c.

#define PredicateLockHashPartitionLock (   hashcode  )     ((LWLockId) (FirstPredicateLockMgrLock + PredicateLockHashPartition(hashcode)))
#define PredicateLockTargetTagHashCode (   predicatelocktargettag  )     (tag_hash((predicatelocktargettag), sizeof(PREDICATELOCKTARGETTAG)))
#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 SxactIsCommitted (   sxact  )     (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)
#define SxactIsDeferrableWaiting (   sxact  )     (((sxact)->flags & SXACT_FLAG_DEFERRABLE_WAITING) != 0)

Definition at line 272 of file predicate.c.

Referenced by ReleasePredicateLocks().

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

Definition at line 249 of file predicate.c.

Referenced by ReleaseOneSerializableXact(), and ReleasePredicateLocks().

#define SxactIsPrepared (   sxact  )     (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)
#define SxactIsReadOnly (   sxact  )     (((sxact)->flags & SXACT_FLAG_READ_ONLY) != 0)
#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 274 of file predicate.c.

Referenced by GetSafeSnapshot(), and ReleasePredicateLocks().

#define TargetTagIsCoveredBy (   covered_target,
  covering_target 
)
Value:
((GET_PREDICATELOCKTARGETTAG_RELATION(covered_target) == /* (2) */  \
      GET_PREDICATELOCKTARGETTAG_RELATION(covering_target))             \
     && (GET_PREDICATELOCKTARGETTAG_OFFSET(covering_target) ==          \
         InvalidOffsetNumber)                                /* (3) */  \
     && (((GET_PREDICATELOCKTARGETTAG_OFFSET(covered_target) !=         \
           InvalidOffsetNumber)                              /* (4a) */ \
          && (GET_PREDICATELOCKTARGETTAG_PAGE(covering_target) ==       \
              GET_PREDICATELOCKTARGETTAG_PAGE(covered_target)))         \
         || ((GET_PREDICATELOCKTARGETTAG_PAGE(covering_target) ==       \
              InvalidBlockNumber)                            /* (4b) */ \
             && (GET_PREDICATELOCKTARGETTAG_PAGE(covered_target)        \
                 != InvalidBlockNumber)))                               \
     && (GET_PREDICATELOCKTARGETTAG_DB(covered_target) ==    /* (1) */  \
         GET_PREDICATELOCKTARGETTAG_DB(covering_target)))

Definition at line 218 of file predicate.c.

Referenced by DeleteChildTargetLocks().


Typedef Documentation

Definition at line 337 of file predicate.c.


Function Documentation

void AtPrepare_PredicateLocks ( void   ) 

Definition at line 4729 of file predicate.c.

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

Referenced by PrepareTransaction().

{
    PREDICATELOCK *predlock;
    SERIALIZABLEXACT *sxact;
    TwoPhasePredicateRecord record;
    TwoPhasePredicateXactRecord *xactRecord;
    TwoPhasePredicateLockRecord *lockRecord;

    sxact = MySerializableXact;
    xactRecord = &(record.data.xactRecord);
    lockRecord = &(record.data.lockRecord);

    if (MySerializableXact == InvalidSerializableXact)
        return;

    /* Generate a xact record for our SERIALIZABLEXACT */
    record.type = TWOPHASEPREDICATERECORD_XACT;
    xactRecord->xmin = MySerializableXact->xmin;
    xactRecord->flags = MySerializableXact->flags;

    /*
     * Note that we don't include the list of conflicts in our out in the
     * statefile, because new conflicts can be added even after the
     * transaction prepares. We'll just make a conservative assumption during
     * recovery instead.
     */

    RegisterTwoPhaseRecord(TWOPHASE_RM_PREDICATELOCK_ID, 0,
                           &record, sizeof(record));

    /*
     * Generate a lock record for each lock.
     *
     * To do this, we need to walk the predicate lock list in our sxact rather
     * than using the local predicate lock table because the latter is not
     * guaranteed to be accurate.
     */
    LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);

    predlock = (PREDICATELOCK *)
        SHMQueueNext(&(sxact->predicateLocks),
                     &(sxact->predicateLocks),
                     offsetof(PREDICATELOCK, xactLink));

    while (predlock != NULL)
    {
        record.type = TWOPHASEPREDICATERECORD_LOCK;
        lockRecord->target = predlock->tag.myTarget->tag;

        RegisterTwoPhaseRecord(TWOPHASE_RM_PREDICATELOCK_ID, 0,
                               &record, sizeof(record));

        predlock = (PREDICATELOCK *)
            SHMQueueNext(&(sxact->predicateLocks),
                         &(predlock->xactLink),
                         offsetof(PREDICATELOCK, xactLink));
    }

    LWLockRelease(SerializablePredicateLockListLock);
}

static bool CheckAndPromotePredicateLockRequest ( const PREDICATELOCKTARGETTAG reqtag  )  [static]

Definition at line 2170 of file predicate.c.

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

Referenced by PredicateLockAcquire().

{
    PREDICATELOCKTARGETTAG targettag,
                nexttag,
                promotiontag;
    LOCALPREDICATELOCK *parentlock;
    bool        found,
                promote;

    promote = false;

    targettag = *reqtag;

    /* check parents iteratively */
    while (GetParentPredicateLockTag(&targettag, &nexttag))
    {
        targettag = nexttag;
        parentlock = (LOCALPREDICATELOCK *) hash_search(LocalPredicateLockHash,
                                                        &targettag,
                                                        HASH_ENTER,
                                                        &found);
        if (!found)
        {
            parentlock->held = false;
            parentlock->childLocks = 1;
        }
        else
            parentlock->childLocks++;

        if (parentlock->childLocks >=
            PredicateLockPromotionThreshold(&targettag))
        {
            /*
             * We should promote to this parent lock. Continue to check its
             * ancestors, however, both to get their child counts right and to
             * check whether we should just go ahead and promote to one of
             * them.
             */
            promotiontag = targettag;
            promote = true;
        }
    }

    if (promote)
    {
        /* acquire coarsest ancestor eligible for promotion */
        PredicateLockAcquire(&promotiontag);
        return true;
    }
    else
        return false;
}

void CheckForSerializableConflictIn ( Relation  relation,
HeapTuple  tuple,
Buffer  buffer 
)

Definition at line 4249 of file predicate.c.

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

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

{
    PREDICATELOCKTARGETTAG targettag;

    if (!SerializationNeededForWrite(relation))
        return;

    /* Check if someone else has already decided that we need to die */
    if (SxactIsDoomed(MySerializableXact))
        ereport(ERROR,
                (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
                 errmsg("could not serialize access due to read/write dependencies among transactions"),
                 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict in checking."),
                 errhint("The transaction might succeed if retried.")));

    /*
     * We're doing a write which might cause rw-conflicts now or later.
     * Memorize that fact.
     */
    MyXactDidWrite = true;

    /*
     * It is important that we check for locks from the finest granularity to
     * the coarsest granularity, so that granularity promotion doesn't cause
     * us to miss a lock.  The new (coarser) lock will be acquired before the
     * old (finer) locks are released.
     *
     * It is not possible to take and hold a lock across the checks for all
     * granularities because each target could be in a separate partition.
     */
    if (tuple != NULL)
    {
        SET_PREDICATELOCKTARGETTAG_TUPLE(targettag,
                                         relation->rd_node.dbNode,
                                         relation->rd_id,
                         ItemPointerGetBlockNumber(&(tuple->t_data->t_ctid)),
                        ItemPointerGetOffsetNumber(&(tuple->t_data->t_ctid)),
                                      HeapTupleHeaderGetXmin(tuple->t_data));
        CheckTargetForConflictsIn(&targettag);
    }

    if (BufferIsValid(buffer))
    {
        SET_PREDICATELOCKTARGETTAG_PAGE(targettag,
                                        relation->rd_node.dbNode,
                                        relation->rd_id,
                                        BufferGetBlockNumber(buffer));
        CheckTargetForConflictsIn(&targettag);
    }

    SET_PREDICATELOCKTARGETTAG_RELATION(targettag,
                                        relation->rd_node.dbNode,
                                        relation->rd_id);
    CheckTargetForConflictsIn(&targettag);
}

void CheckForSerializableConflictOut ( bool  visible,
Relation  relation,
HeapTuple  tuple,
Buffer  buffer,
Snapshot  snapshot 
)

Definition at line 3868 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, SERIALIZABLEXACT::lastCommitBeforeSnapshot, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), SERIALIZABLEXID::myXact, NULL, OldSerXidGetMinConflictCommitSeqNo(), RWConflictExists(), SERIALIZABLEXACT::SeqNo, SerializableXactHashLock, SerializationNeededForRead(), SHMQueueEmpty(), SubTransGetTopmostTransaction(), 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(), and heapgettup().

{
    TransactionId xid;
    SERIALIZABLEXIDTAG sxidtag;
    SERIALIZABLEXID *sxid;
    SERIALIZABLEXACT *sxact;
    HTSV_Result htsvResult;

    if (!SerializationNeededForRead(relation, snapshot))
        return;

    /* Check if someone else has already decided that we need to die */
    if (SxactIsDoomed(MySerializableXact))
    {
        ereport(ERROR,
                (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
                 errmsg("could not serialize access due to read/write dependencies among transactions"),
                 errdetail_internal("Reason code: Canceled on identification as a pivot, during conflict out checking."),
                 errhint("The transaction might succeed if retried.")));
    }

    /*
     * Check to see whether the tuple has been written to by a concurrent
     * transaction, either to create it not visible to us, or to delete it
     * while it is visible to us.  The "visible" bool indicates whether the
     * tuple is visible to us, while HeapTupleSatisfiesVacuum checks what else
     * is going on with it.
     */
    htsvResult = HeapTupleSatisfiesVacuum(tuple->t_data, TransactionXmin, buffer);
    switch (htsvResult)
    {
        case HEAPTUPLE_LIVE:
            if (visible)
                return;
            xid = HeapTupleHeaderGetXmin(tuple->t_data);
            break;
        case HEAPTUPLE_RECENTLY_DEAD:
            if (!visible)
                return;
            xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
            break;
        case HEAPTUPLE_DELETE_IN_PROGRESS:
            xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
            break;
        case HEAPTUPLE_INSERT_IN_PROGRESS:
            xid = HeapTupleHeaderGetXmin(tuple->t_data);
            break;
        case HEAPTUPLE_DEAD:
            return;
        default:

            /*
             * The only way to get to this default clause is if a new value is
             * added to the enum type without adding it to this switch
             * statement.  That's a bug, so elog.
             */
            elog(ERROR, "unrecognized return value from HeapTupleSatisfiesVacuum: %u", htsvResult);

            /*
             * In spite of having all enum values covered and calling elog on
             * this default, some compilers think this is a code path which
             * allows xid to be used below without initialization. Silence
             * that warning.
             */
            xid = InvalidTransactionId;
    }
    Assert(TransactionIdIsValid(xid));
    Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));

    /*
     * Find top level xid.  Bail out if xid is too early to be a conflict, or
     * if it's our own xid.
     */
    if (TransactionIdEquals(xid, GetTopTransactionIdIfAny()))
        return;
    xid = SubTransGetTopmostTransaction(xid);
    if (TransactionIdPrecedes(xid, TransactionXmin))
        return;
    if (TransactionIdEquals(xid, GetTopTransactionIdIfAny()))
        return;

    /*
     * Find sxact or summarized info for the top level xid.
     */
    sxidtag.xid = xid;
    LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    sxid = (SERIALIZABLEXID *)
        hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
    if (!sxid)
    {
        /*
         * Transaction not found in "normal" SSI structures.  Check whether it
         * got pushed out to SLRU storage for "old committed" transactions.
         */
        SerCommitSeqNo conflictCommitSeqNo;

        conflictCommitSeqNo = OldSerXidGetMinConflictCommitSeqNo(xid);
        if (conflictCommitSeqNo != 0)
        {
            if (conflictCommitSeqNo != InvalidSerCommitSeqNo
                && (!SxactIsReadOnly(MySerializableXact)
                    || conflictCommitSeqNo
                    <= MySerializableXact->SeqNo.lastCommitBeforeSnapshot))
                ereport(ERROR,
                        (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
                         errmsg("could not serialize access due to read/write dependencies among transactions"),
                         errdetail_internal("Reason code: Canceled on conflict out to old pivot %u.", xid),
                      errhint("The transaction might succeed if retried.")));

            if (SxactHasSummaryConflictIn(MySerializableXact)
                || !SHMQueueEmpty(&MySerializableXact->inConflicts))
                ereport(ERROR,
                        (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
                         errmsg("could not serialize access due to read/write dependencies among transactions"),
                         errdetail_internal("Reason code: Canceled on identification as a pivot, with conflict out to old committed transaction %u.", xid),
                      errhint("The transaction might succeed if retried.")));

            MySerializableXact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
        }

        /* It's not serializable or otherwise not important. */
        LWLockRelease(SerializableXactHashLock);
        return;
    }
    sxact = sxid->myXact;
    Assert(TransactionIdEquals(sxact->topXid, xid));
    if (sxact == MySerializableXact || SxactIsDoomed(sxact))
    {
        /* Can't conflict with ourself or a transaction that will roll back. */
        LWLockRelease(SerializableXactHashLock);
        return;
    }

    /*
     * We have a conflict out to a transaction which has a conflict out to a
     * summarized transaction.  That summarized transaction must have
     * committed first, and we can't tell when it committed in relation to our
     * snapshot acquisition, so something needs to be canceled.
     */
    if (SxactHasSummaryConflictOut(sxact))
    {
        if (!SxactIsPrepared(sxact))
        {
            sxact->flags |= SXACT_FLAG_DOOMED;
            LWLockRelease(SerializableXactHashLock);
            return;
        }
        else
        {
            LWLockRelease(SerializableXactHashLock);
            ereport(ERROR,
                    (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
                     errmsg("could not serialize access due to read/write dependencies among transactions"),
                     errdetail_internal("Reason code: Canceled on conflict out to old pivot."),
                     errhint("The transaction might succeed if retried.")));
        }
    }

    /*
     * If this is a read-only transaction and the writing transaction has
     * committed, and it doesn't have a rw-conflict to a transaction which
     * committed before it, no conflict.
     */
    if (SxactIsReadOnly(MySerializableXact)
        && SxactIsCommitted(sxact)
        && !SxactHasSummaryConflictOut(sxact)
        && (!SxactHasConflictOut(sxact)
            || MySerializableXact->SeqNo.lastCommitBeforeSnapshot < sxact->SeqNo.earliestOutConflictCommit))
    {
        /* Read-only transaction will appear to run first.  No conflict. */
        LWLockRelease(SerializableXactHashLock);
        return;
    }

    if (!XidIsConcurrent(xid))
    {
        /* This write was already in our snapshot; no conflict. */
        LWLockRelease(SerializableXactHashLock);
        return;
    }

    if (RWConflictExists(MySerializableXact, sxact))
    {
        /* We don't want duplicate conflict records in the list. */
        LWLockRelease(SerializableXactHashLock);
        return;
    }

    /*
     * Flag the conflict.  But first, if this conflict creates a dangerous
     * structure, ereport an error.
     */
    FlagRWConflict(MySerializableXact, sxact);
    LWLockRelease(SerializableXactHashLock);
}

void CheckPointPredicate ( void   ) 

Definition at line 1026 of file predicate.c.

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

Referenced by CheckPointGuts().

{
    int         tailPage;

    LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);

    /* Exit quickly if the SLRU is currently not in use. */
    if (oldSerXidControl->headPage < 0)
    {
        LWLockRelease(OldSerXidLock);
        return;
    }

    if (TransactionIdIsValid(oldSerXidControl->tailXid))
    {
        /* We can truncate the SLRU up to the page containing tailXid */
        tailPage = OldSerXidPage(oldSerXidControl->tailXid);
    }
    else
    {
        /*
         * The SLRU is no longer needed. Truncate to head before we set head
         * invalid.
         *
         * XXX: It's possible that the SLRU is not needed again until XID
         * wrap-around has happened, so that the segment containing headPage
         * that we leave behind will appear to be new again. In that case it
         * won't be removed until XID horizon advances enough to make it
         * current again.
         */
        tailPage = oldSerXidControl->headPage;
        oldSerXidControl->headPage = -1;
    }

    LWLockRelease(OldSerXidLock);

    /* Truncate away pages that are no longer required */
    SimpleLruTruncate(OldSerXidSlruCtl, tailPage);

    /*
     * Flush dirty SLRU pages to disk
     *
     * This is not actually necessary from a correctness point of view. We do
     * it merely as a debugging aid.
     *
     * We're doing this after the truncation to avoid writing pages right
     * before deleting the file in which they sit, which would be completely
     * pointless.
     */
    SimpleLruFlush(OldSerXidSlruCtl, true);
}

void CheckTableForSerializableConflictIn ( Relation  relation  ) 

Definition at line 4334 of file predicate.c.

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

Referenced by ExecuteTruncate(), and heap_drop_with_catalog().

{
    HASH_SEQ_STATUS seqstat;
    PREDICATELOCKTARGET *target;
    Oid         dbId;
    Oid         heapId;
    int         i;

    /*
     * Bail out quickly if there are no serializable transactions running.
     * It's safe to check this without taking locks because the caller is
     * holding an ACCESS EXCLUSIVE lock on the relation.  No new locks which
     * would matter here can be acquired while that is held.
     */
    if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
        return;

    if (!SerializationNeededForWrite(relation))
        return;

    /*
     * We're doing a write which might cause rw-conflicts now or later.
     * Memorize that fact.
     */
    MyXactDidWrite = true;

    Assert(relation->rd_index == NULL); /* not an index relation */

    dbId = relation->rd_node.dbNode;
    heapId = relation->rd_id;

    LWLockAcquire(SerializablePredicateLockListLock, LW_EXCLUSIVE);
    for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
        LWLockAcquire(FirstPredicateLockMgrLock + i, LW_SHARED);
    LWLockAcquire(SerializableXactHashLock, LW_SHARED);

    /* Scan through target list */
    hash_seq_init(&seqstat, PredicateLockTargetHash);

    while ((target = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
    {
        PREDICATELOCK *predlock;

        /*
         * Check whether this is a target which needs attention.
         */
        if (GET_PREDICATELOCKTARGETTAG_RELATION(target->tag) != heapId)
            continue;           /* wrong relation id */
        if (GET_PREDICATELOCKTARGETTAG_DB(target->tag) != dbId)
            continue;           /* wrong database id */

        /*
         * Loop through locks for this target and flag conflicts.
         */
        predlock = (PREDICATELOCK *)
            SHMQueueNext(&(target->predicateLocks),
                         &(target->predicateLocks),
                         offsetof(PREDICATELOCK, targetLink));
        while (predlock)
        {
            PREDICATELOCK *nextpredlock;

            nextpredlock = (PREDICATELOCK *)
                SHMQueueNext(&(target->predicateLocks),
                             &(predlock->targetLink),
                             offsetof(PREDICATELOCK, targetLink));

            if (predlock->tag.myXact != MySerializableXact
              && !RWConflictExists(predlock->tag.myXact, MySerializableXact))
            {
                FlagRWConflict(predlock->tag.myXact, MySerializableXact);
            }

            predlock = nextpredlock;
        }
    }

    /* Release locks in reverse order */
    LWLockRelease(SerializableXactHashLock);
    for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
        LWLockRelease(FirstPredicateLockMgrLock + i);
    LWLockRelease(SerializablePredicateLockListLock);
}

static void CheckTargetForConflictsIn ( PREDICATELOCKTARGETTAG targettag  )  [static]

Definition at line 4071 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(), SerializablePredicateLockListLock, SerializableXactHashLock, SHMQueueDelete(), SHMQueueNext(), SxactIsCommitted, SxactIsDoomed, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdPrecedes(), and PREDICATELOCK::xactLink.

Referenced by CheckForSerializableConflictIn().

{
    uint32      targettaghash;
    LWLockId    partitionLock;
    PREDICATELOCKTARGET *target;
    PREDICATELOCK *predlock;
    PREDICATELOCK *mypredlock = NULL;
    PREDICATELOCKTAG mypredlocktag;

    Assert(MySerializableXact != InvalidSerializableXact);

    /*
     * The same hash and LW lock apply to the lock target and the lock itself.
     */
    targettaghash = PredicateLockTargetTagHashCode(targettag);
    partitionLock = PredicateLockHashPartitionLock(targettaghash);
    LWLockAcquire(partitionLock, LW_SHARED);
    target = (PREDICATELOCKTARGET *)
        hash_search_with_hash_value(PredicateLockTargetHash,
                                    targettag, targettaghash,
                                    HASH_FIND, NULL);
    if (!target)
    {
        /* Nothing has this target locked; we're done here. */
        LWLockRelease(partitionLock);
        return;
    }

    /*
     * Each lock for an overlapping transaction represents a conflict: a
     * rw-dependency in to this transaction.
     */
    predlock = (PREDICATELOCK *)
        SHMQueueNext(&(target->predicateLocks),
                     &(target->predicateLocks),
                     offsetof(PREDICATELOCK, targetLink));
    LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    while (predlock)
    {
        SHM_QUEUE  *predlocktargetlink;
        PREDICATELOCK *nextpredlock;
        SERIALIZABLEXACT *sxact;

        predlocktargetlink = &(predlock->targetLink);
        nextpredlock = (PREDICATELOCK *)
            SHMQueueNext(&(target->predicateLocks),
                         predlocktargetlink,
                         offsetof(PREDICATELOCK, targetLink));

        sxact = predlock->tag.myXact;
        if (sxact == MySerializableXact)
        {
            /*
             * If we're getting a write lock on a tuple, we don't need a
             * predicate (SIREAD) lock on the same tuple. We can safely remove
             * our SIREAD lock, but we'll defer doing so until after the loop
             * because that requires upgrading to an exclusive partition lock.
             *
             * We can't use this optimization within a subtransaction because
             * the subtransaction could roll back, and we would be left
             * without any lock at the top level.
             */
            if (!IsSubTransaction()
                && GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
            {
                mypredlock = predlock;
                mypredlocktag = predlock->tag;
            }
        }
        else if (!SxactIsDoomed(sxact)
                 && (!SxactIsCommitted(sxact)
                     || TransactionIdPrecedes(GetTransactionSnapshot()->xmin,
                                              sxact->finishedBefore))
                 && !RWConflictExists(sxact, MySerializableXact))
        {
            LWLockRelease(SerializableXactHashLock);
            LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);

            /*
             * Re-check after getting exclusive lock because the other
             * transaction may have flagged a conflict.
             */
            if (!SxactIsDoomed(sxact)
                && (!SxactIsCommitted(sxact)
                    || TransactionIdPrecedes(GetTransactionSnapshot()->xmin,
                                             sxact->finishedBefore))
                && !RWConflictExists(sxact, MySerializableXact))
            {
                FlagRWConflict(sxact, MySerializableXact);
            }

            LWLockRelease(SerializableXactHashLock);
            LWLockAcquire(SerializableXactHashLock, LW_SHARED);
        }

        predlock = nextpredlock;
    }
    LWLockRelease(SerializableXactHashLock);
    LWLockRelease(partitionLock);

    /*
     * If we found one of our own SIREAD locks to remove, remove it now.
     *
     * At this point our transaction already has an ExclusiveRowLock on the
     * relation, so we are OK to drop the predicate lock on the tuple, if
     * found, without fearing that another write against the tuple will occur
     * before the MVCC information makes it to the buffer.
     */
    if (mypredlock != NULL)
    {
        uint32      predlockhashcode;
        PREDICATELOCK *rmpredlock;

        LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
        LWLockAcquire(partitionLock, LW_EXCLUSIVE);
        LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);

        /*
         * Remove the predicate lock from shared memory, if it wasn't removed
         * while the locks were released.  One way that could happen is from
         * autovacuum cleaning up an index.
         */
        predlockhashcode = PredicateLockHashCodeFromTargetHashCode
            (&mypredlocktag, targettaghash);
        rmpredlock = (PREDICATELOCK *)
            hash_search_with_hash_value(PredicateLockHash,
                                        &mypredlocktag,
                                        predlockhashcode,
                                        HASH_FIND, NULL);
        if (rmpredlock != NULL)
        {
            Assert(rmpredlock == mypredlock);

            SHMQueueDelete(&(mypredlock->targetLink));
            SHMQueueDelete(&(mypredlock->xactLink));

            rmpredlock = (PREDICATELOCK *)
                hash_search_with_hash_value(PredicateLockHash,
                                            &mypredlocktag,
                                            predlockhashcode,
                                            HASH_REMOVE, NULL);
            Assert(rmpredlock == mypredlock);

            RemoveTargetIfNoLongerUsed(target, targettaghash);
        }

        LWLockRelease(SerializableXactHashLock);
        LWLockRelease(partitionLock);
        LWLockRelease(SerializablePredicateLockListLock);

        if (rmpredlock != NULL)
        {
            /*
             * Remove entry in local lock table if it exists. It's OK if it
             * doesn't exist; that means the lock was transferred to a new
             * target by a different backend.
             */
            hash_search_with_hash_value(LocalPredicateLockHash,
                                        targettag, targettaghash,
                                        HASH_REMOVE, NULL);

            DecrementParentLocks(targettag);
        }
    }
}

static void ClearOldPredicateLocks ( void   )  [static]

Definition at line 3509 of file predicate.c.

References Assert, PredXactListData::CanPartialClearThrough, PREDICATELOCK::commitSeqNo, SERIALIZABLEXACT::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(), SerializableFinishedListLock, SerializablePredicateLockListLock, SerializableXactHashLock, SHMQueueDelete(), SHMQueueNext(), PredXactListData::SxactGlobalXmin, SxactIsReadOnly, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, TransactionIdIsValid, TransactionIdPrecedesOrEquals(), and PREDICATELOCK::xactLink.

Referenced by ReleasePredicateLocks().

{
    SERIALIZABLEXACT *finishedSxact;
    PREDICATELOCK *predlock;

    /*
     * Loop through finished transactions. They are in commit order, so we can
     * stop as soon as we find one that's still interesting.
     */
    LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);
    finishedSxact = (SERIALIZABLEXACT *)
        SHMQueueNext(FinishedSerializableTransactions,
                     FinishedSerializableTransactions,
                     offsetof(SERIALIZABLEXACT, finishedLink));
    LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    while (finishedSxact)
    {
        SERIALIZABLEXACT *nextSxact;

        nextSxact = (SERIALIZABLEXACT *)
            SHMQueueNext(FinishedSerializableTransactions,
                         &(finishedSxact->finishedLink),
                         offsetof(SERIALIZABLEXACT, finishedLink));
        if (!TransactionIdIsValid(PredXact->SxactGlobalXmin)
            || TransactionIdPrecedesOrEquals(finishedSxact->finishedBefore,
                                             PredXact->SxactGlobalXmin))
        {
            /*
             * This transaction committed before any in-progress transaction
             * took its snapshot. It's no longer interesting.
             */
            LWLockRelease(SerializableXactHashLock);
            SHMQueueDelete(&(finishedSxact->finishedLink));
            ReleaseOneSerializableXact(finishedSxact, false, false);
            LWLockAcquire(SerializableXactHashLock, LW_SHARED);
        }
        else if (finishedSxact->commitSeqNo > PredXact->HavePartialClearedThrough
           && finishedSxact->commitSeqNo <= PredXact->CanPartialClearThrough)
        {
            /*
             * Any active transactions that took their snapshot before this
             * transaction committed are read-only, so we can clear part of
             * its state.
             */
            LWLockRelease(SerializableXactHashLock);

            if (SxactIsReadOnly(finishedSxact))
            {
                /* A read-only transaction can be removed entirely */
                SHMQueueDelete(&(finishedSxact->finishedLink));
                ReleaseOneSerializableXact(finishedSxact, false, false);
            }
            else
            {
                /*
                 * A read-write transaction can only be partially cleared. We
                 * need to keep the SERIALIZABLEXACT but can release the
                 * SIREAD locks and conflicts in.
                 */
                ReleaseOneSerializableXact(finishedSxact, true, false);
            }

            PredXact->HavePartialClearedThrough = finishedSxact->commitSeqNo;
            LWLockAcquire(SerializableXactHashLock, LW_SHARED);
        }
        else
        {
            /* Still interesting. */
            break;
        }
        finishedSxact = nextSxact;
    }
    LWLockRelease(SerializableXactHashLock);

    /*
     * Loop through predicate locks on dummy transaction for summarized data.
     */
    LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
    predlock = (PREDICATELOCK *)
        SHMQueueNext(&OldCommittedSxact->predicateLocks,
                     &OldCommittedSxact->predicateLocks,
                     offsetof(PREDICATELOCK, xactLink));
    while (predlock)
    {
        PREDICATELOCK *nextpredlock;
        bool        canDoPartialCleanup;

        nextpredlock = (PREDICATELOCK *)
            SHMQueueNext(&OldCommittedSxact->predicateLocks,
                         &predlock->xactLink,
                         offsetof(PREDICATELOCK, xactLink));

        LWLockAcquire(SerializableXactHashLock, LW_SHARED);
        Assert(predlock->commitSeqNo != 0);
        Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
        canDoPartialCleanup = (predlock->commitSeqNo <= PredXact->CanPartialClearThrough);
        LWLockRelease(SerializableXactHashLock);

        /*
         * If this lock originally belonged to an old enough transaction, we
         * can release it.
         */
        if (canDoPartialCleanup)
        {
            PREDICATELOCKTAG tag;
            PREDICATELOCKTARGET *target;
            PREDICATELOCKTARGETTAG targettag;
            uint32      targettaghash;
            LWLockId    partitionLock;

            tag = predlock->tag;
            target = tag.myTarget;
            targettag = target->tag;
            targettaghash = PredicateLockTargetTagHashCode(&targettag);
            partitionLock = PredicateLockHashPartitionLock(targettaghash);

            LWLockAcquire(partitionLock, LW_EXCLUSIVE);

            SHMQueueDelete(&(predlock->targetLink));
            SHMQueueDelete(&(predlock->xactLink));

            hash_search_with_hash_value(PredicateLockHash, &tag,
                                PredicateLockHashCodeFromTargetHashCode(&tag,
                                                              targettaghash),
                                        HASH_REMOVE, NULL);
            RemoveTargetIfNoLongerUsed(target, targettaghash);

            LWLockRelease(partitionLock);
        }

        predlock = nextpredlock;
    }

    LWLockRelease(SerializablePredicateLockListLock);
    LWLockRelease(SerializableFinishedListLock);
}

static bool CoarserLockCovers ( const PREDICATELOCKTARGETTAG newtargettag  )  [static]

Definition at line 1958 of file predicate.c.

References GetParentPredicateLockTag(), and PredicateLockExists().

Referenced by PredicateLockAcquire().

{
    PREDICATELOCKTARGETTAG targettag,
                parenttag;

    targettag = *newtargettag;

    /* check parents iteratively until no more */
    while (GetParentPredicateLockTag(&targettag, &parenttag))
    {
        targettag = parenttag;
        if (PredicateLockExists(&targettag))
            return true;
    }

    /* no more parents to check; lock is not covered */
    return false;
}

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

Definition at line 2297 of file predicate.c.

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

Referenced by predicatelock_twophase_recover(), and PredicateLockAcquire().

{
    PREDICATELOCKTARGET *target;
    PREDICATELOCKTAG locktag;
    PREDICATELOCK *lock;
    LWLockId    partitionLock;
    bool        found;

    partitionLock = PredicateLockHashPartitionLock(targettaghash);

    LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
    LWLockAcquire(partitionLock, LW_EXCLUSIVE);

    /* Make sure that the target is represented. */
    target = (PREDICATELOCKTARGET *)
        hash_search_with_hash_value(PredicateLockTargetHash,
                                    targettag, targettaghash,
                                    HASH_ENTER_NULL, &found);
    if (!target)
        ereport(ERROR,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of shared memory"),
                 errhint("You might need to increase max_pred_locks_per_transaction.")));
    if (!found)
        SHMQueueInit(&(target->predicateLocks));

    /* We've got the sxact and target, make sure they're joined. */
    locktag.myTarget = target;
    locktag.myXact = sxact;
    lock = (PREDICATELOCK *)
        hash_search_with_hash_value(PredicateLockHash, &locktag,
            PredicateLockHashCodeFromTargetHashCode(&locktag, targettaghash),
                                    HASH_ENTER_NULL, &found);
    if (!lock)
        ereport(ERROR,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of shared memory"),
                 errhint("You might need to increase max_pred_locks_per_transaction.")));

    if (!found)
    {
        SHMQueueInsertBefore(&(target->predicateLocks), &(lock->targetLink));
        SHMQueueInsertBefore(&(sxact->predicateLocks),
                             &(lock->xactLink));
        lock->commitSeqNo = InvalidSerCommitSeqNo;
    }

    LWLockRelease(partitionLock);
    LWLockRelease(SerializablePredicateLockListLock);
}

static SERIALIZABLEXACT * CreatePredXact ( void   )  [static]
static void DecrementParentLocks ( const PREDICATELOCKTARGETTAG targettag  )  [static]

Definition at line 2235 of file predicate.c.

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

Referenced by CheckTargetForConflictsIn(), and DeleteChildTargetLocks().

{
    PREDICATELOCKTARGETTAG parenttag,
                nexttag;

    parenttag = *targettag;

    while (GetParentPredicateLockTag(&parenttag, &nexttag))
    {
        uint32      targettaghash;
        LOCALPREDICATELOCK *parentlock,
                   *rmlock PG_USED_FOR_ASSERTS_ONLY;

        parenttag = nexttag;
        targettaghash = PredicateLockTargetTagHashCode(&parenttag);
        parentlock = (LOCALPREDICATELOCK *)
            hash_search_with_hash_value(LocalPredicateLockHash,
                                        &parenttag, targettaghash,
                                        HASH_FIND, NULL);

        /*
         * There's a small chance the parent lock doesn't exist in the lock
         * table. This can happen if we prematurely removed it because an
         * index split caused the child refcount to be off.
         */
        if (parentlock == NULL)
            continue;

        parentlock->childLocks--;

        /*
         * Under similar circumstances the parent lock's refcount might be
         * zero. This only happens if we're holding that lock (otherwise we
         * would have removed the entry).
         */
        if (parentlock->childLocks < 0)
        {
            Assert(parentlock->held);
            parentlock->childLocks = 0;
        }

        if ((parentlock->childLocks == 0) && (!parentlock->held))
        {
            rmlock = (LOCALPREDICATELOCK *)
                hash_search_with_hash_value(LocalPredicateLockHash,
                                            &parenttag, targettaghash,
                                            HASH_REMOVE, NULL);
            Assert(rmlock == parentlock);
        }
    }
}

static void DeleteChildTargetLocks ( const PREDICATELOCKTARGETTAG newtargettag  )  [static]

Definition at line 2059 of file predicate.c.

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

Referenced by PredicateLockAcquire().

{
    SERIALIZABLEXACT *sxact;
    PREDICATELOCK *predlock;

    LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
    sxact = MySerializableXact;
    predlock = (PREDICATELOCK *)
        SHMQueueNext(&(sxact->predicateLocks),
                     &(sxact->predicateLocks),
                     offsetof(PREDICATELOCK, xactLink));
    while (predlock)
    {
        SHM_QUEUE  *predlocksxactlink;
        PREDICATELOCK *nextpredlock;
        PREDICATELOCKTAG oldlocktag;
        PREDICATELOCKTARGET *oldtarget;
        PREDICATELOCKTARGETTAG oldtargettag;

        predlocksxactlink = &(predlock->xactLink);
        nextpredlock = (PREDICATELOCK *)
            SHMQueueNext(&(sxact->predicateLocks),
                         predlocksxactlink,
                         offsetof(PREDICATELOCK, xactLink));

        oldlocktag = predlock->tag;
        Assert(oldlocktag.myXact == sxact);
        oldtarget = oldlocktag.myTarget;
        oldtargettag = oldtarget->tag;

        if (TargetTagIsCoveredBy(oldtargettag, *newtargettag))
        {
            uint32      oldtargettaghash;
            LWLockId    partitionLock;
            PREDICATELOCK *rmpredlock PG_USED_FOR_ASSERTS_ONLY;

            oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
            partitionLock = PredicateLockHashPartitionLock(oldtargettaghash);

            LWLockAcquire(partitionLock, LW_EXCLUSIVE);

            SHMQueueDelete(predlocksxactlink);
            SHMQueueDelete(&(predlock->targetLink));
            rmpredlock = hash_search_with_hash_value
                (PredicateLockHash,
                 &oldlocktag,
                 PredicateLockHashCodeFromTargetHashCode(&oldlocktag,
                                                         oldtargettaghash),
                 HASH_REMOVE, NULL);
            Assert(rmpredlock == predlock);

            RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);

            LWLockRelease(partitionLock);

            DecrementParentLocks(&oldtargettag);
        }

        predlock = nextpredlock;
    }
    LWLockRelease(SerializablePredicateLockListLock);
}

static void DeleteLockTarget ( PREDICATELOCKTARGET target,
uint32  targettaghash 
) [static]

Definition at line 2530 of file predicate.c.

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

Referenced by TransferPredicateLocksToNewTarget().

{
    PREDICATELOCK *predlock;
    SHM_QUEUE  *predlocktargetlink;
    PREDICATELOCK *nextpredlock;
    bool        found;

    Assert(LWLockHeldByMe(SerializablePredicateLockListLock));
    Assert(LWLockHeldByMe(PredicateLockHashPartitionLock(targettaghash)));

    predlock = (PREDICATELOCK *)
        SHMQueueNext(&(target->predicateLocks),
                     &(target->predicateLocks),
                     offsetof(PREDICATELOCK, targetLink));
    LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    while (predlock)
    {
        predlocktargetlink = &(predlock->targetLink);
        nextpredlock = (PREDICATELOCK *)
            SHMQueueNext(&(target->predicateLocks),
                         predlocktargetlink,
                         offsetof(PREDICATELOCK, targetLink));

        SHMQueueDelete(&(predlock->xactLink));
        SHMQueueDelete(&(predlock->targetLink));

        hash_search_with_hash_value
            (PredicateLockHash,
             &predlock->tag,
             PredicateLockHashCodeFromTargetHashCode(&predlock->tag,
                                                     targettaghash),
             HASH_REMOVE, &found);
        Assert(found);

        predlock = nextpredlock;
    }
    LWLockRelease(SerializableXactHashLock);

    /* Remove the target itself, if possible. */
    RemoveTargetIfNoLongerUsed(target, targettaghash);
}

static void DropAllPredicateLocksFromTable ( Relation  relation,
bool  transfer 
) [static]

Definition at line 2816 of file predicate.c.

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

Referenced by TransferPredicateLocksToHeapRelation().

{
    HASH_SEQ_STATUS seqstat;
    PREDICATELOCKTARGET *oldtarget;
    PREDICATELOCKTARGET *heaptarget;
    Oid         dbId;
    Oid         relId;
    Oid         heapId;
    int         i;
    bool        isIndex;
    bool        found;
    uint32      heaptargettaghash;

    /*
     * Bail out quickly if there are no serializable transactions running.
     * It's safe to check this without taking locks because the caller is
     * holding an ACCESS EXCLUSIVE lock on the relation.  No new locks which
     * would matter here can be acquired while that is held.
     */
    if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
        return;

    if (!PredicateLockingNeededForRelation(relation))
        return;

    dbId = relation->rd_node.dbNode;
    relId = relation->rd_id;
    if (relation->rd_index == NULL)
    {
        isIndex = false;
        heapId = relId;
    }
    else
    {
        isIndex = true;
        heapId = relation->rd_index->indrelid;
    }
    Assert(heapId != InvalidOid);
    Assert(transfer || !isIndex);       /* index OID only makes sense with
                                         * transfer */

    /* Retrieve first time needed, then keep. */
    heaptargettaghash = 0;
    heaptarget = NULL;

    /* Acquire locks on all lock partitions */
    LWLockAcquire(SerializablePredicateLockListLock, LW_EXCLUSIVE);
    for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
        LWLockAcquire(FirstPredicateLockMgrLock + i, LW_EXCLUSIVE);
    LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);

    /*
     * Remove the dummy entry to give us scratch space, so we know we'll be
     * able to create the new lock target.
     */
    if (transfer)
        RemoveScratchTarget(true);

    /* Scan through target map */
    hash_seq_init(&seqstat, PredicateLockTargetHash);

    while ((oldtarget = (PREDICATELOCKTARGET *) hash_seq_search(&seqstat)))
    {
        PREDICATELOCK *oldpredlock;

        /*
         * Check whether this is a target which needs attention.
         */
        if (GET_PREDICATELOCKTARGETTAG_RELATION(oldtarget->tag) != relId)
            continue;           /* wrong relation id */
        if (GET_PREDICATELOCKTARGETTAG_DB(oldtarget->tag) != dbId)
            continue;           /* wrong database id */
        if (transfer && !isIndex
            && GET_PREDICATELOCKTARGETTAG_TYPE(oldtarget->tag) == PREDLOCKTAG_RELATION)
            continue;           /* already the right lock */

        /*
         * If we made it here, we have work to do.  We make sure the heap
         * relation lock exists, then we walk the list of predicate locks for
         * the old target we found, moving all locks to the heap relation lock
         * -- unless they already hold that.
         */

        /*
         * First make sure we have the heap relation target.  We only need to
         * do this once.
         */
        if (transfer && heaptarget == NULL)
        {
            PREDICATELOCKTARGETTAG heaptargettag;

            SET_PREDICATELOCKTARGETTAG_RELATION(heaptargettag, dbId, heapId);
            heaptargettaghash = PredicateLockTargetTagHashCode(&heaptargettag);
            heaptarget = hash_search_with_hash_value(PredicateLockTargetHash,
                                                     &heaptargettag,
                                                     heaptargettaghash,
                                                     HASH_ENTER, &found);
            if (!found)
                SHMQueueInit(&heaptarget->predicateLocks);
        }

        /*
         * Loop through all the locks on the old target, replacing them with
         * locks on the new target.
         */
        oldpredlock = (PREDICATELOCK *)
            SHMQueueNext(&(oldtarget->predicateLocks),
                         &(oldtarget->predicateLocks),
                         offsetof(PREDICATELOCK, targetLink));
        while (oldpredlock)
        {
            PREDICATELOCK *nextpredlock;
            PREDICATELOCK *newpredlock;
            SerCommitSeqNo oldCommitSeqNo;
            SERIALIZABLEXACT *oldXact;

            nextpredlock = (PREDICATELOCK *)
                SHMQueueNext(&(oldtarget->predicateLocks),
                             &(oldpredlock->targetLink),
                             offsetof(PREDICATELOCK, targetLink));

            /*
             * Remove the old lock first. This avoids the chance of running
             * out of lock structure entries for the hash table.
             */
            oldCommitSeqNo = oldpredlock->commitSeqNo;
            oldXact = oldpredlock->tag.myXact;

            SHMQueueDelete(&(oldpredlock->xactLink));

            /*
             * No need for retail delete from oldtarget list, we're removing
             * the whole target anyway.
             */
            hash_search(PredicateLockHash,
                        &oldpredlock->tag,
                        HASH_REMOVE, &found);
            Assert(found);

            if (transfer)
            {
                PREDICATELOCKTAG newpredlocktag;

                newpredlocktag.myTarget = heaptarget;
                newpredlocktag.myXact = oldXact;
                newpredlock = (PREDICATELOCK *)
                    hash_search_with_hash_value(PredicateLockHash,
                                                &newpredlocktag,
                     PredicateLockHashCodeFromTargetHashCode(&newpredlocktag,
                                                          heaptargettaghash),
                                                HASH_ENTER,
                                                &found);
                if (!found)
                {
                    SHMQueueInsertBefore(&(heaptarget->predicateLocks),
                                         &(newpredlock->targetLink));
                    SHMQueueInsertBefore(&(newpredlocktag.myXact->predicateLocks),
                                         &(newpredlock->xactLink));
                    newpredlock->commitSeqNo = oldCommitSeqNo;
                }
                else
                {
                    if (newpredlock->commitSeqNo < oldCommitSeqNo)
                        newpredlock->commitSeqNo = oldCommitSeqNo;
                }

                Assert(newpredlock->commitSeqNo != 0);
                Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
                       || (newpredlock->tag.myXact == OldCommittedSxact));
            }

            oldpredlock = nextpredlock;
        }

        hash_search(PredicateLockTargetHash, &oldtarget->tag, HASH_REMOVE,
                    &found);
        Assert(found);
    }

    /* Put the scratch entry back */
    if (transfer)
        RestoreScratchTarget(true);

    /* Release locks in reverse order */
    LWLockRelease(SerializableXactHashLock);
    for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
        LWLockRelease(FirstPredicateLockMgrLock + i);
    LWLockRelease(SerializablePredicateLockListLock);
}

static SERIALIZABLEXACT * FirstPredXact ( void   )  [static]
static void FlagRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
) [static]

Definition at line 4426 of file predicate.c.

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

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

{
    Assert(reader != writer);

    /* First, see if this conflict causes failure. */
    OnConflict_CheckForSerializationFailure(reader, writer);

    /* Actually do the conflict flagging. */
    if (reader == OldCommittedSxact)
        writer->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
    else if (writer == OldCommittedSxact)
        reader->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
    else
        SetRWConflict(reader, writer);
}

static void FlagSxactUnsafe ( SERIALIZABLEXACT sxact  )  [static]

Definition at line 721 of file predicate.c.

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

Referenced by ReleasePredicateLocks().

{
    RWConflict  conflict,
                nextConflict;

    Assert(SxactIsReadOnly(sxact));
    Assert(!SxactIsROSafe(sxact));

    sxact->flags |= SXACT_FLAG_RO_UNSAFE;

    /*
     * We know this isn't a safe snapshot, so we can stop looking for other
     * potential conflicts.
     */
    conflict = (RWConflict)
        SHMQueueNext(&sxact->possibleUnsafeConflicts,
                     &sxact->possibleUnsafeConflicts,
                     offsetof(RWConflictData, inLink));
    while (conflict)
    {
        nextConflict = (RWConflict)
            SHMQueueNext(&sxact->possibleUnsafeConflicts,
                         &conflict->inLink,
                         offsetof(RWConflictData, inLink));

        Assert(!SxactIsReadOnly(conflict->sxactOut));
        Assert(sxact == conflict->sxactIn);

        ReleaseRWConflict(conflict);

        conflict = nextConflict;
    }
}

static bool GetParentPredicateLockTag ( const PREDICATELOCKTARGETTAG tag,
PREDICATELOCKTARGETTAG parent 
) [static]
PredicateLockData* GetPredicateLockStatusData ( void   ) 

Definition at line 1385 of file predicate.c.

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

Referenced by pg_lock_status().

{
    PredicateLockData *data;
    int         i;
    int         els,
                el;
    HASH_SEQ_STATUS seqstat;
    PREDICATELOCK *predlock;

    data = (PredicateLockData *) palloc(sizeof(PredicateLockData));

    /*
     * To ensure consistency, take simultaneous locks on all partition locks
     * in ascending order, then SerializableXactHashLock.
     */
    for (i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
        LWLockAcquire(FirstPredicateLockMgrLock + i, LW_SHARED);
    LWLockAcquire(SerializableXactHashLock, LW_SHARED);

    /* Get number of locks and allocate appropriately-sized arrays. */
    els = hash_get_num_entries(PredicateLockHash);
    data->nelements = els;
    data->locktags = (PREDICATELOCKTARGETTAG *)
        palloc(sizeof(PREDICATELOCKTARGETTAG) * els);
    data->xacts = (SERIALIZABLEXACT *)
        palloc(sizeof(SERIALIZABLEXACT) * els);


    /* Scan through PredicateLockHash and copy contents */
    hash_seq_init(&seqstat, PredicateLockHash);

    el = 0;

    while ((predlock = (PREDICATELOCK *) hash_seq_search(&seqstat)))
    {
        data->locktags[el] = predlock->tag.myTarget->tag;
        data->xacts[el] = *predlock->tag.myXact;
        el++;
    }

    Assert(el == els);

    /* Release locks in reverse order */
    LWLockRelease(SerializableXactHashLock);
    for (i = NUM_PREDICATELOCK_PARTITIONS - 1; i >= 0; i--)
        LWLockRelease(FirstPredicateLockMgrLock + i);

    return data;
}

static Snapshot GetSafeSnapshot ( Snapshot  snapshot  )  [static]

Definition at line 1500 of file predicate.c.

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

Referenced by GetSerializableTransactionSnapshot().

{
    Snapshot    snapshot;

    Assert(XactReadOnly && XactDeferrable);

    while (true)
    {
        /*
         * GetSerializableTransactionSnapshotInt is going to call
         * GetSnapshotData, so we need to provide it the static snapshot area
         * our caller passed to us.  The pointer returned is actually the same
         * one passed to it, but we avoid assuming that here.
         */
        snapshot = GetSerializableTransactionSnapshotInt(origSnapshot,
                                                       InvalidTransactionId);

        if (MySerializableXact == InvalidSerializableXact)
            return snapshot;    /* no concurrent r/w xacts; it's safe */

        LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);

        /*
         * Wait for concurrent transactions to finish. Stop early if one of
         * them marked us as conflicted.
         */
        MySerializableXact->flags |= SXACT_FLAG_DEFERRABLE_WAITING;
        while (!(SHMQueueEmpty(&MySerializableXact->possibleUnsafeConflicts) ||
                 SxactIsROUnsafe(MySerializableXact)))
        {
            LWLockRelease(SerializableXactHashLock);
            ProcWaitForSignal();
            LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
        }
        MySerializableXact->flags &= ~SXACT_FLAG_DEFERRABLE_WAITING;

        if (!SxactIsROUnsafe(MySerializableXact))
        {
            LWLockRelease(SerializableXactHashLock);
            break;              /* success */
        }

        LWLockRelease(SerializableXactHashLock);

        /* else, need to retry... */
        ereport(DEBUG2,
                (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
                 errmsg("deferrable snapshot was unsafe; trying a new one")));
        ReleasePredicateLocks(false);
    }

    /*
     * Now we have a safe snapshot, so we don't need to do any further checks.
     */
    Assert(SxactIsROSafe(MySerializableXact));
    ReleasePredicateLocks(false);

    return snapshot;
}

Snapshot GetSerializableTransactionSnapshot ( Snapshot  snapshot  ) 

Definition at line 1572 of file predicate.c.

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

Referenced by GetTransactionSnapshot().

{
    Assert(IsolationIsSerializable());

    /*
     * Can't use serializable mode while recovery is still active, as it is,
     * for example, on a hot standby.  We could get here despite the check
     * in check_XactIsoLevel() if default_transaction_isolation is set to
     * serializable, so phrase the hint accordingly.
     */
    if (RecoveryInProgress())
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("cannot use serializable mode in a hot standby"),
                 errdetail("\"default_transaction_isolation\" is set to \"serializable\"."),
                 errhint("You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default.")));

    /*
     * A special optimization is available for SERIALIZABLE READ ONLY
     * DEFERRABLE transactions -- we can wait for a suitable snapshot and
     * thereby avoid all SSI overhead once it's running.
     */
    if (XactReadOnly && XactDeferrable)
        return GetSafeSnapshot(snapshot);

    return GetSerializableTransactionSnapshotInt(snapshot,
                                                 InvalidTransactionId);
}

static Snapshot GetSerializableTransactionSnapshotInt ( Snapshot  snapshot,
TransactionId  sourcexid 
) [static]

Definition at line 1641 of file predicate.c.

References Assert, SERIALIZABLEXACT::commitSeqNo, CreatePredXact(), HASHCTL::entrysize, ereport, errcode(), errdetail(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FirstPredXact(), SERIALIZABLEXACT::flags, GET_VXID_FROM_PGPROC, GetSnapshotData(), GetTopTransactionIdIfAny(), HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, SERIALIZABLEXACT::inConflicts, InvalidSerializableXact, 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, SerializableXactHashLock, SetPossibleUnsafeConflict(), SHMQueueElemInit(), SHMQueueInit(), SummarizeOldestCommittedSxact(), PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactIsCommitted, SxactIsDoomed, SxactIsReadOnly, SERIALIZABLEXACT::topXid, TransactionIdEquals, TransactionIdFollows(), TransactionIdIsValid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, XactReadOnly, SERIALIZABLEXACT::xmin, and SnapshotData::xmin.

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

{
    PGPROC     *proc;
    VirtualTransactionId vxid;
    SERIALIZABLEXACT *sxact,
               *othersxact;
    HASHCTL     hash_ctl;

    /* We only do this for serializable transactions.  Once. */
    Assert(MySerializableXact == InvalidSerializableXact);

    Assert(!RecoveryInProgress());

    proc = MyProc;
    Assert(proc != NULL);
    GET_VXID_FROM_PGPROC(vxid, *proc);

    /*
     * First we get the sxact structure, which may involve looping and access
     * to the "finished" list to free a structure for use.
     *
     * We must hold SerializableXactHashLock when taking/checking the snapshot
     * to avoid race conditions, for much the same reasons that
     * GetSnapshotData takes the ProcArrayLock.  Since we might have to
     * release SerializableXactHashLock to call SummarizeOldestCommittedSxact,
     * this means we have to create the sxact first, which is a bit annoying
     * (in particular, an elog(ERROR) in procarray.c would cause us to leak
     * the sxact).  Consider refactoring to avoid this.
     */
#ifdef TEST_OLDSERXID
    SummarizeOldestCommittedSxact();
#endif
    LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
    do
    {
        sxact = CreatePredXact();
        /* If null, push out committed sxact to SLRU summary & retry. */
        if (!sxact)
        {
            LWLockRelease(SerializableXactHashLock);
            SummarizeOldestCommittedSxact();
            LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
        }
    } while (!sxact);

    /* Get the snapshot, or check that it's safe to use */
    if (!TransactionIdIsValid(sourcexid))
        snapshot = GetSnapshotData(snapshot);
    else if (!ProcArrayInstallImportedXmin(snapshot->xmin, sourcexid))
    {
        ReleasePredXact(sxact);
        LWLockRelease(SerializableXactHashLock);
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("could not import the requested snapshot"),
               errdetail("The source transaction %u is not running anymore.",
                         sourcexid)));
    }

    /*
     * If there are no serializable transactions which are not read-only, we
     * can "opt out" of predicate locking and conflict checking for a
     * read-only transaction.
     *
     * The reason this is safe is that a read-only transaction can only become
     * part of a dangerous structure if it overlaps a writable transaction
     * which in turn overlaps a writable transaction which committed before
     * the read-only transaction started.  A new writable transaction can
     * overlap this one, but it can't meet the other condition of overlapping
     * a transaction which committed before this one started.
     */
    if (XactReadOnly && PredXact->WritableSxactCount == 0)
    {
        ReleasePredXact(sxact);
        LWLockRelease(SerializableXactHashLock);
        return snapshot;
    }

    /* Maintain serializable global xmin info. */
    if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
    {
        Assert(PredXact->SxactGlobalXminCount == 0);
        PredXact->SxactGlobalXmin = snapshot->xmin;
        PredXact->SxactGlobalXminCount = 1;
        OldSerXidSetActiveSerXmin(snapshot->xmin);
    }
    else if (TransactionIdEquals(snapshot->xmin, PredXact->SxactGlobalXmin))
    {
        Assert(PredXact->SxactGlobalXminCount > 0);
        PredXact->SxactGlobalXminCount++;
    }
    else
    {
        Assert(TransactionIdFollows(snapshot->xmin, PredXact->SxactGlobalXmin));
    }

    /* Initialize the structure. */
    sxact->vxid = vxid;
    sxact->SeqNo.lastCommitBeforeSnapshot = PredXact->LastSxactCommitSeqNo;
    sxact->prepareSeqNo = InvalidSerCommitSeqNo;
    sxact->commitSeqNo = InvalidSerCommitSeqNo;
    SHMQueueInit(&(sxact->outConflicts));
    SHMQueueInit(&(sxact->inConflicts));
    SHMQueueInit(&(sxact->possibleUnsafeConflicts));
    sxact->topXid = GetTopTransactionIdIfAny();
    sxact->finishedBefore = InvalidTransactionId;
    sxact->xmin = snapshot->xmin;
    sxact->pid = MyProcPid;
    SHMQueueInit(&(sxact->predicateLocks));
    SHMQueueElemInit(&(sxact->finishedLink));
    sxact->flags = 0;
    if (XactReadOnly)
    {
        sxact->flags |= SXACT_FLAG_READ_ONLY;

        /*
         * Register all concurrent r/w transactions as possible conflicts; if
         * all of them commit without any outgoing conflicts to earlier
         * transactions then this snapshot can be deemed safe (and we can run
         * without tracking predicate locks).
         */
        for (othersxact = FirstPredXact();
             othersxact != NULL;
             othersxact = NextPredXact(othersxact))
        {
            if (!SxactIsCommitted(othersxact)
                && !SxactIsDoomed(othersxact)
                && !SxactIsReadOnly(othersxact))
            {
                SetPossibleUnsafeConflict(sxact, othersxact);
            }
        }
    }
    else
    {
        ++(PredXact->WritableSxactCount);
        Assert(PredXact->WritableSxactCount <=
               (MaxBackends + max_prepared_xacts));
    }

    MySerializableXact = sxact;
    MyXactDidWrite = false;     /* haven't written anything yet */

    LWLockRelease(SerializableXactHashLock);

    /* Initialize the backend-local hash table of parent locks */
    Assert(LocalPredicateLockHash == NULL);
    MemSet(&hash_ctl, 0, sizeof(hash_ctl));
    hash_ctl.keysize = sizeof(PREDICATELOCKTARGETTAG);
    hash_ctl.entrysize = sizeof(LOCALPREDICATELOCK);
    hash_ctl.hash = tag_hash;
    LocalPredicateLockHash = hash_create("Local predicate lock",
                                         max_predicate_locks_per_xact,
                                         &hash_ctl,
                                         HASH_ELEM | HASH_FUNCTION);

    return snapshot;
}

void InitPredicateLocks ( void   ) 

Definition at line 1091 of file predicate.c.

References PredXactListData::activeList, RWConflictPoolHeaderData::availableList, PredXactListData::availableList, PredXactListData::CanPartialClearThrough, SERIALIZABLEXACT::commitSeqNo, CreatePredXact(), RWConflictPoolHeaderData::element, PredXactListData::element, HASHCTL::entrysize, ereport, errcode(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, FirstNormalSerCommitSeqNo, SERIALIZABLEXACT::flags, HASHCTL::hash, HASH_ELEM, HASH_ENTER, HASH_FUNCTION, HASH_PARTITION, hash_search(), PredXactListData::HavePartialClearedThrough, i, SERIALIZABLEXACT::inConflicts, HASHCTL::keysize, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, PredXactListElementData::link, max_prepared_xacts, MaxBackends, MemSet, mul_size(), NPREDICATELOCKTARGETENTS, NULL, HASHCTL::num_partitions, PredXactListData::OldCommittedSxact, OldSerXidInit(), SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, PredXactListDataSize, PredXactListElementDataSize, SERIALIZABLEXACT::prepareSeqNo, RWConflictDataSize, RWConflictPoolHeaderDataSize, ScratchPartitionLock, ScratchTargetTagHash, SERIALIZABLEXACT::SeqNo, SetInvalidVirtualTransactionId, ShmemAlloc(), ShmemInitHash(), ShmemInitStruct(), SHMQueueInit(), SHMQueueInsertBefore(), PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SERIALIZABLEXACT::topXid, SERIALIZABLEXACT::vxid, PredXactListData::WritableSxactCount, and SERIALIZABLEXACT::xmin.

Referenced by CreateSharedMemoryAndSemaphores().

{
    HASHCTL     info;
    int         hash_flags;
    long        max_table_size;
    Size        requestSize;
    bool        found;

    /*
     * Compute size of predicate lock target hashtable. Note these
     * calculations must agree with PredicateLockShmemSize!
     */
    max_table_size = NPREDICATELOCKTARGETENTS();

    /*
     * Allocate hash table for PREDICATELOCKTARGET structs.  This stores
     * per-predicate-lock-target information.
     */
    MemSet(&info, 0, sizeof(info));
    info.keysize = sizeof(PREDICATELOCKTARGETTAG);
    info.entrysize = sizeof(PREDICATELOCKTARGET);
    info.hash = tag_hash;
    info.num_partitions = NUM_PREDICATELOCK_PARTITIONS;
    hash_flags = (HASH_ELEM | HASH_FUNCTION | HASH_PARTITION | HASH_FIXED_SIZE);

    PredicateLockTargetHash = ShmemInitHash("PREDICATELOCKTARGET hash",
                                            max_table_size,
                                            max_table_size,
                                            &info,
                                            hash_flags);

    /* Assume an average of 2 xacts per target */
    max_table_size *= 2;

    /*
     * Reserve a dummy entry in the hash table; we use it to make sure there's
     * always one entry available when we need to split or combine a page,
     * because running out of space there could mean aborting a
     * non-serializable transaction.
     */
    hash_search(PredicateLockTargetHash, &ScratchTargetTag, HASH_ENTER, NULL);

    /*
     * Allocate hash table for PREDICATELOCK structs.  This stores per
     * xact-lock-of-a-target information.
     */
    MemSet(&info, 0, sizeof(info));
    info.keysize = sizeof(PREDICATELOCKTAG);
    info.entrysize = sizeof(PREDICATELOCK);
    info.hash = predicatelock_hash;
    info.num_partitions = NUM_PREDICATELOCK_PARTITIONS;
    hash_flags = (HASH_ELEM | HASH_FUNCTION | HASH_PARTITION | HASH_FIXED_SIZE);

    PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
                                      max_table_size,
                                      max_table_size,
                                      &info,
                                      hash_flags);

    /*
     * Compute size for serializable transaction hashtable. Note these
     * calculations must agree with PredicateLockShmemSize!
     */
    max_table_size = (MaxBackends + max_prepared_xacts);

    /*
     * Allocate a list to hold information on transactions participating in
     * predicate locking.
     *
     * Assume an average of 10 predicate locking transactions per backend.
     * This allows aggressive cleanup while detail is present before data must
     * be summarized for storage in SLRU and the "dummy" transaction.
     */
    max_table_size *= 10;

    PredXact = ShmemInitStruct("PredXactList",
                               PredXactListDataSize,
                               &found);
    if (!found)
    {
        int         i;

        SHMQueueInit(&PredXact->availableList);
        SHMQueueInit(&PredXact->activeList);
        PredXact->SxactGlobalXmin = InvalidTransactionId;
        PredXact->SxactGlobalXminCount = 0;
        PredXact->WritableSxactCount = 0;
        PredXact->LastSxactCommitSeqNo = FirstNormalSerCommitSeqNo - 1;
        PredXact->CanPartialClearThrough = 0;
        PredXact->HavePartialClearedThrough = 0;
        requestSize = mul_size((Size) max_table_size,
                               PredXactListElementDataSize);
        PredXact->element = ShmemAlloc(requestSize);
        if (PredXact->element == NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
             errmsg("not enough shared memory for elements of data structure"
                    " \"%s\" (%lu bytes requested)",
                    "PredXactList", (unsigned long) requestSize)));
        /* Add all elements to available list, clean. */
        memset(PredXact->element, 0, requestSize);
        for (i = 0; i < max_table_size; i++)
        {
            SHMQueueInsertBefore(&(PredXact->availableList),
                                 &(PredXact->element[i].link));
        }
        PredXact->OldCommittedSxact = CreatePredXact();
        SetInvalidVirtualTransactionId(PredXact->OldCommittedSxact->vxid);
        PredXact->OldCommittedSxact->prepareSeqNo = 0;
        PredXact->OldCommittedSxact->commitSeqNo = 0;
        PredXact->OldCommittedSxact->SeqNo.lastCommitBeforeSnapshot = 0;
        SHMQueueInit(&PredXact->OldCommittedSxact->outConflicts);
        SHMQueueInit(&PredXact->OldCommittedSxact->inConflicts);
        SHMQueueInit(&PredXact->OldCommittedSxact->predicateLocks);
        SHMQueueInit(&PredXact->OldCommittedSxact->finishedLink);
        SHMQueueInit(&PredXact->OldCommittedSxact->possibleUnsafeConflicts);
        PredXact->OldCommittedSxact->topXid = InvalidTransactionId;
        PredXact->OldCommittedSxact->finishedBefore = InvalidTransactionId;
        PredXact->OldCommittedSxact->xmin = InvalidTransactionId;
        PredXact->OldCommittedSxact->flags = SXACT_FLAG_COMMITTED;
        PredXact->OldCommittedSxact->pid = 0;
    }
    /* This never changes, so let's keep a local copy. */
    OldCommittedSxact = PredXact->OldCommittedSxact;

    /*
     * Allocate hash table for SERIALIZABLEXID structs.  This stores per-xid
     * information for serializable transactions which have accessed data.
     */
    MemSet(&info, 0, sizeof(info));
    info.keysize = sizeof(SERIALIZABLEXIDTAG);
    info.entrysize = sizeof(SERIALIZABLEXID);
    info.hash = tag_hash;
    hash_flags = (HASH_ELEM | HASH_FUNCTION | HASH_FIXED_SIZE);

    SerializableXidHash = ShmemInitHash("SERIALIZABLEXID hash",
                                        max_table_size,
                                        max_table_size,
                                        &info,
                                        hash_flags);

    /*
     * Allocate space for tracking rw-conflicts in lists attached to the
     * transactions.
     *
     * Assume an average of 5 conflicts per transaction.  Calculations suggest
     * that this will prevent resource exhaustion in even the most pessimal
     * loads up to max_connections = 200 with all 200 connections pounding the
     * database with serializable transactions.  Beyond that, there may be
     * occasional transactions canceled when trying to flag conflicts. That's
     * probably OK.
     */
    max_table_size *= 5;

    RWConflictPool = ShmemInitStruct("RWConflictPool",
                                     RWConflictPoolHeaderDataSize,
                                     &found);
    if (!found)
    {
        int         i;

        SHMQueueInit(&RWConflictPool->availableList);
        requestSize = mul_size((Size) max_table_size,
                               RWConflictDataSize);
        RWConflictPool->element = ShmemAlloc(requestSize);
        if (RWConflictPool->element == NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
             errmsg("not enough shared memory for elements of data structure"
                    " \"%s\" (%lu bytes requested)",
                    "RWConflictPool", (unsigned long) requestSize)));
        /* Add all elements to available list, clean. */
        memset(RWConflictPool->element, 0, requestSize);
        for (i = 0; i < max_table_size; i++)
        {
            SHMQueueInsertBefore(&(RWConflictPool->availableList),
                                 &(RWConflictPool->element[i].outLink));
        }
    }

    /*
     * Create or attach to the header for the list of finished serializable
     * transactions.
     */
    FinishedSerializableTransactions = (SHM_QUEUE *)
        ShmemInitStruct("FinishedSerializableTransactions",
                        sizeof(SHM_QUEUE),
                        &found);
    if (!found)
        SHMQueueInit(FinishedSerializableTransactions);

    /*
     * Initialize the SLRU storage for old committed serializable
     * transactions.
     */
    OldSerXidInit();

    /* Pre-calculate the hash and partition lock of the scratch entry */
    ScratchTargetTagHash = PredicateLockTargetTagHashCode(&ScratchTargetTag);
    ScratchPartitionLock = PredicateLockHashPartitionLock(ScratchTargetTagHash);
}

static SERIALIZABLEXACT * NextPredXact ( SERIALIZABLEXACT sxact  )  [static]
static void OldSerXidAdd ( TransactionId  xid,
SerCommitSeqNo  minConflictCommitSeqNo 
) [static]

Definition at line 822 of file predicate.c.

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

Referenced by SummarizeOldestCommittedSxact().

{
    TransactionId tailXid;
    int         targetPage;
    int         slotno;
    int         firstZeroPage;
    bool        isNewPage;

    Assert(TransactionIdIsValid(xid));

    targetPage = OldSerXidPage(xid);

    LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);

    /*
     * If no serializable transactions are active, there shouldn't be anything
     * to push out to the SLRU.  Hitting this assert would mean there's
     * something wrong with the earlier cleanup logic.
     */
    tailXid = oldSerXidControl->tailXid;
    Assert(TransactionIdIsValid(tailXid));

    /*
     * If the SLRU is currently unused, zero out the whole active region from
     * tailXid to headXid before taking it into use. Otherwise zero out only
     * any new pages that enter the tailXid-headXid range as we advance
     * headXid.
     */
    if (oldSerXidControl->headPage < 0)
    {
        firstZeroPage = OldSerXidPage(tailXid);
        isNewPage = true;
    }
    else
    {
        firstZeroPage = OldSerXidNextPage(oldSerXidControl->headPage);
        isNewPage = OldSerXidPagePrecedesLogically(oldSerXidControl->headPage,
                                                   targetPage);
    }

    if (!TransactionIdIsValid(oldSerXidControl->headXid)
        || TransactionIdFollows(xid, oldSerXidControl->headXid))
        oldSerXidControl->headXid = xid;
    if (isNewPage)
        oldSerXidControl->headPage = targetPage;

    /*
     * Give a warning if we're about to run out of SLRU pages.
     *
     * slru.c has a maximum of 64k segments, with 32 (SLRU_PAGES_PER_SEGMENT)
     * pages each. We need to store a 64-bit integer for each Xid, and with
     * default 8k block size, 65536*32 pages is only enough to cover 2^30
     * XIDs. If we're about to hit that limit and wrap around, warn the user.
     *
     * To avoid spamming the user, we only give one warning when we've used 1
     * billion XIDs, and stay silent until the situation is fixed and the
     * number of XIDs used falls below 800 million again.
     *
     * XXX: We have no safeguard to actually *prevent* the wrap-around,
     * though. All you get is a warning.
     */
    if (oldSerXidControl->warningIssued)
    {
        TransactionId lowWatermark;

        lowWatermark = tailXid + 800000000;
        if (lowWatermark < FirstNormalTransactionId)
            lowWatermark = FirstNormalTransactionId;
        if (TransactionIdPrecedes(xid, lowWatermark))
            oldSerXidControl->warningIssued = false;
    }
    else
    {
        TransactionId highWatermark;

        highWatermark = tailXid + 1000000000;
        if (highWatermark < FirstNormalTransactionId)
            highWatermark = FirstNormalTransactionId;
        if (TransactionIdFollows(xid, highWatermark))
        {
            oldSerXidControl->warningIssued = true;
            ereport(WARNING,
                    (errmsg("memory for serializable conflict tracking is nearly exhausted"),
                     errhint("There might be an idle transaction or a forgotten prepared transaction causing this.")));
        }
    }

    if (isNewPage)
    {
        /* Initialize intervening pages. */
        while (firstZeroPage != targetPage)
        {
            (void) SimpleLruZeroPage(OldSerXidSlruCtl, firstZeroPage);
            firstZeroPage = OldSerXidNextPage(firstZeroPage);
        }
        slotno = SimpleLruZeroPage(OldSerXidSlruCtl, targetPage);
    }
    else
        slotno = SimpleLruReadPage(OldSerXidSlruCtl, targetPage, true, xid);

    OldSerXidValue(slotno, xid) = minConflictCommitSeqNo;
    OldSerXidSlruCtl->shared->page_dirty[slotno] = true;

    LWLockRelease(OldSerXidLock);
}

static SerCommitSeqNo OldSerXidGetMinConflictCommitSeqNo ( TransactionId  xid  )  [static]

Definition at line 934 of file predicate.c.

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

Referenced by CheckForSerializableConflictOut().

{
    TransactionId headXid;
    TransactionId tailXid;
    SerCommitSeqNo val;
    int         slotno;

    Assert(TransactionIdIsValid(xid));

    LWLockAcquire(OldSerXidLock, LW_SHARED);
    headXid = oldSerXidControl->headXid;
    tailXid = oldSerXidControl->tailXid;
    LWLockRelease(OldSerXidLock);

    if (!TransactionIdIsValid(headXid))
        return 0;

    Assert(TransactionIdIsValid(tailXid));

    if (TransactionIdPrecedes(xid, tailXid)
        || TransactionIdFollows(xid, headXid))
        return 0;

    /*
     * The following function must be called without holding OldSerXidLock,
     * but will return with that lock held, which must then be released.
     */
    slotno = SimpleLruReadPage_ReadOnly(OldSerXidSlruCtl,
                                        OldSerXidPage(xid), xid);
    val = OldSerXidValue(slotno, xid);
    LWLockRelease(OldSerXidLock);
    return val;
}

static void OldSerXidInit ( void   )  [static]

Definition at line 785 of file predicate.c.

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

Referenced by InitPredicateLocks().

{
    bool        found;

    /*
     * Set up SLRU management of the pg_serial data.
     */
    OldSerXidSlruCtl->PagePrecedes = OldSerXidPagePrecedesLogically;
    SimpleLruInit(OldSerXidSlruCtl, "OldSerXid SLRU Ctl",
                  NUM_OLDSERXID_BUFFERS, 0, OldSerXidLock, "pg_serial");
    /* Override default assumption that writes should be fsync'd */
    OldSerXidSlruCtl->do_fsync = false;

    /*
     * Create or attach to the OldSerXidControl structure.
     */
    oldSerXidControl = (OldSerXidControl)
        ShmemInitStruct("OldSerXidControlData", sizeof(OldSerXidControlData), &found);

    if (!found)
    {
        /*
         * Set control information to reflect empty SLRU.
         */
        oldSerXidControl->headPage = -1;
        oldSerXidControl->headXid = InvalidTransactionId;
        oldSerXidControl->tailXid = InvalidTransactionId;
        oldSerXidControl->warningIssued = false;
    }
}

static bool OldSerXidPagePrecedesLogically ( int  p,
int  q 
) [static]

Definition at line 762 of file predicate.c.

References Assert, and OLDSERXID_MAX_PAGE.

Referenced by OldSerXidAdd().

{
    int         diff;

    /*
     * We have to compare modulo (OLDSERXID_MAX_PAGE+1)/2.  Both inputs should
     * be in the range 0..OLDSERXID_MAX_PAGE.
     */
    Assert(p >= 0 && p <= OLDSERXID_MAX_PAGE);
    Assert(q >= 0 && q <= OLDSERXID_MAX_PAGE);

    diff = p - q;
    if (diff >= ((OLDSERXID_MAX_PAGE + 1) / 2))
        diff -= OLDSERXID_MAX_PAGE + 1;
    else if (diff < -((int) (OLDSERXID_MAX_PAGE + 1) / 2))
        diff += OLDSERXID_MAX_PAGE + 1;
    return diff < 0;
}

static void OldSerXidSetActiveSerXmin ( TransactionId  xid  )  [static]

Definition at line 975 of file predicate.c.

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

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

{
    LWLockAcquire(OldSerXidLock, LW_EXCLUSIVE);

    /*
     * When no sxacts are active, nothing overlaps, set the xid values to
     * invalid to show that there are no valid entries.  Don't clear headPage,
     * though.  A new xmin might still land on that page, and we don't want to
     * repeatedly zero out the same page.
     */
    if (!TransactionIdIsValid(xid))
    {
        oldSerXidControl->tailXid = InvalidTransactionId;
        oldSerXidControl->headXid = InvalidTransactionId;
        LWLockRelease(OldSerXidLock);
        return;
    }

    /*
     * When we're recovering prepared transactions, the global xmin might move
     * backwards depending on the order they're recovered. Normally that's not
     * OK, but during recovery no serializable transactions will commit, so
     * the SLRU is empty and we can get away with it.
     */
    if (RecoveryInProgress())
    {
        Assert(oldSerXidControl->headPage < 0);
        if (!TransactionIdIsValid(oldSerXidControl->tailXid)
            || TransactionIdPrecedes(xid, oldSerXidControl->tailXid))
        {
            oldSerXidControl->tailXid = xid;
        }
        LWLockRelease(OldSerXidLock);
        return;
    }

    Assert(!TransactionIdIsValid(oldSerXidControl->tailXid)
           || TransactionIdFollows(xid, oldSerXidControl->tailXid));

    oldSerXidControl->tailXid = xid;

    LWLockRelease(OldSerXidLock);
}

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

Definition at line 4461 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(), offsetof, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::prepareSeqNo, SERIALIZABLEXACT::SeqNo, SerializableXactHashLock, SHMQueueNext(), SxactHasConflictOut, SxactHasSummaryConflictIn, SxactHasSummaryConflictOut, RWConflictData::sxactIn, SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, RWConflictData::sxactOut, and SERIALIZABLEXACT::topXid.

Referenced by FlagRWConflict().

{
    bool        failure;
    RWConflict  conflict;

    Assert(LWLockHeldByMe(SerializableXactHashLock));

    failure = false;

    /*------------------------------------------------------------------------
     * Check for already-committed writer with rw-conflict out flagged
     * (conflict-flag on W means that T2 committed before W):
     *
     *      R ------> W ------> T2
     *          rw        rw
     *
     * That is a dangerous structure, so we must abort. (Since the writer
     * has already committed, we must be the reader)
     *------------------------------------------------------------------------
     */
    if (SxactIsCommitted(writer)
      && (SxactHasConflictOut(writer) || SxactHasSummaryConflictOut(writer)))
        failure = true;

    /*------------------------------------------------------------------------
     * Check whether the writer has become a pivot with an out-conflict
     * committed transaction (T2), and T2 committed first:
     *
     *      R ------> W ------> T2
     *          rw        rw
     *
     * Because T2 must've committed first, there is no anomaly if:
     * - the reader committed before T2
     * - the writer committed before T2
     * - the reader is a READ ONLY transaction and the reader was concurrent
     *   with T2 (= reader acquired its snapshot before T2 committed)
     *
     * We also handle the case that T2 is prepared but not yet committed
     * here. In that case T2 has already checked for conflicts, so if it
     * commits first, making the above conflict real, it's too late for it
     * to abort.
     *------------------------------------------------------------------------
     */
    if (!failure)
    {
        if (SxactHasSummaryConflictOut(writer))
        {
            failure = true;
            conflict = NULL;
        }
        else
            conflict = (RWConflict)
                SHMQueueNext(&writer->outConflicts,
                             &writer->outConflicts,
                             offsetof(RWConflictData, outLink));
        while (conflict)
        {
            SERIALIZABLEXACT *t2 = conflict->sxactIn;

            if (SxactIsPrepared(t2)
                && (!SxactIsCommitted(reader)
                    || t2->prepareSeqNo <= reader->commitSeqNo)
                && (!SxactIsCommitted(writer)
                    || t2->prepareSeqNo <= writer->commitSeqNo)
                && (!SxactIsReadOnly(reader)
              || t2->prepareSeqNo <= reader->SeqNo.lastCommitBeforeSnapshot))
            {
                failure = true;
                break;
            }
            conflict = (RWConflict)
                SHMQueueNext(&writer->outConflicts,
                             &conflict->outLink,
                             offsetof(RWConflictData, outLink));
        }
    }

    /*------------------------------------------------------------------------
     * Check whether the reader has become a pivot with a writer
     * that's committed (or prepared):
     *
     *      T0 ------> R ------> W
     *           rw        rw
     *
     * Because W must've committed first for an anomaly to occur, there is no
     * anomaly if:
     * - T0 committed before the writer
     * - T0 is READ ONLY, and overlaps the writer
     *------------------------------------------------------------------------
     */
    if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
    {
        if (SxactHasSummaryConflictIn(reader))
        {
            failure = true;
            conflict = NULL;
        }
        else
            conflict = (RWConflict)
                SHMQueueNext(&reader->inConflicts,
                             &reader->inConflicts,
                             offsetof(RWConflictData, inLink));
        while (conflict)
        {
            SERIALIZABLEXACT *t0 = conflict->sxactOut;

            if (!SxactIsDoomed(t0)
                && (!SxactIsCommitted(t0)
                    || t0->commitSeqNo >= writer->prepareSeqNo)
                && (!SxactIsReadOnly(t0)
              || t0->SeqNo.lastCommitBeforeSnapshot >= writer->prepareSeqNo))
            {
                failure = true;
                break;
            }
            conflict = (RWConflict)
                SHMQueueNext(&reader->inConflicts,
                             &conflict->inLink,
                             offsetof(RWConflictData, inLink));
        }
    }

    if (failure)
    {
        /*
         * We have to kill a transaction to avoid a possible anomaly from
         * occurring. If the writer is us, we can just ereport() to cause a
         * transaction abort. Otherwise we flag the writer for termination,
         * causing it to abort when it tries to commit. However, if the writer
         * is a prepared transaction, already prepared, we can't abort it
         * anymore, so we have to kill the reader instead.
         */
        if (MySerializableXact == writer)
        {
            LWLockRelease(SerializableXactHashLock);
            ereport(ERROR,
                    (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
                     errmsg("could not serialize access due to read/write dependencies among transactions"),
                     errdetail_internal("Reason code: Canceled on identification as a pivot, during write."),
                     errhint("The transaction might succeed if retried.")));
        }
        else if (SxactIsPrepared(writer))
        {
            LWLockRelease(SerializableXactHashLock);

            /* if we're not the writer, we have to be the reader */
            Assert(MySerializableXact == reader);
            ereport(ERROR,
                    (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
                     errmsg("could not serialize access due to read/write dependencies among transactions"),
                     errdetail_internal("Reason code: Canceled on conflict out to pivot %u, during read.", writer->topXid),
                     errhint("The transaction might succeed if retried.")));
        }
        writer->flags |= SXACT_FLAG_DOOMED;
    }
}

bool PageIsPredicateLocked ( Relation  relation,
BlockNumber  blkno 
)
void PostPrepare_PredicateLocks ( TransactionId  xid  ) 
void PreCommit_CheckForSerializationFailure ( void   ) 

Definition at line 4636 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, SerializableXactHashLock, SHMQueueNext(), SxactIsCommitted, SxactIsDoomed, SxactIsPrepared, SxactIsReadOnly, and RWConflictData::sxactOut.

Referenced by CommitTransaction(), and PrepareTransaction().

{
    RWConflict  nearConflict;

    if (MySerializableXact == InvalidSerializableXact)
        return;

    Assert(IsolationIsSerializable());

    LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);

    /* Check if someone else has already decided that we need to die */
    if (SxactIsDoomed(MySerializableXact))
    {
        LWLockRelease(SerializableXactHashLock);
        ereport(ERROR,
                (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
                 errmsg("could not serialize access due to read/write dependencies among transactions"),
                 errdetail_internal("Reason code: Canceled on identification as a pivot, during commit attempt."),
                 errhint("The transaction might succeed if retried.")));
    }

    nearConflict = (RWConflict)
        SHMQueueNext(&MySerializableXact->inConflicts,
                     &MySerializableXact->inConflicts,
                     offsetof(RWConflictData, inLink));
    while (nearConflict)
    {
        if (!SxactIsCommitted(nearConflict->sxactOut)
            && !SxactIsDoomed(nearConflict->sxactOut))
        {
            RWConflict  farConflict;

            farConflict = (RWConflict)
                SHMQueueNext(&nearConflict->sxactOut->inConflicts,
                             &nearConflict->sxactOut->inConflicts,
                             offsetof(RWConflictData, inLink));
            while (farConflict)
            {
                if (farConflict->sxactOut == MySerializableXact
                    || (!SxactIsCommitted(farConflict->sxactOut)
                        && !SxactIsReadOnly(farConflict->sxactOut)
                        && !SxactIsDoomed(farConflict->sxactOut)))
                {
                    /*
                     * Normally, we kill the pivot transaction to make sure we
                     * make progress if the failing transaction is retried.
                     * However, we can't kill it if it's already prepared, so
                     * in that case we commit suicide instead.
                     */
                    if (SxactIsPrepared(nearConflict->sxactOut))
                    {
                        LWLockRelease(SerializableXactHashLock);
                        ereport(ERROR,
                                (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
                                 errmsg("could not serialize access due to read/write dependencies among transactions"),
                                 errdetail_internal("Reason code: Canceled on commit attempt with conflict in from prepared pivot."),
                                 errhint("The transaction might succeed if retried.")));
                    }
                    nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
                    break;
                }
                farConflict = (RWConflict)
                    SHMQueueNext(&nearConflict->sxactOut->inConflicts,
                                 &farConflict->inLink,
                                 offsetof(RWConflictData, inLink));
            }
        }

        nearConflict = (RWConflict)
            SHMQueueNext(&MySerializableXact->inConflicts,
                         &nearConflict->inLink,
                         offsetof(RWConflictData, inLink));
    }

    MySerializableXact->prepareSeqNo = ++(PredXact->LastSxactCommitSeqNo);
    MySerializableXact->flags |= SXACT_FLAG_PREPARED;

    LWLockRelease(SerializableXactHashLock);
}

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

Definition at line 1359 of file predicate.c.

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

{
    const PREDICATELOCKTAG *predicatelocktag = (const PREDICATELOCKTAG *) key;
    uint32      targethash;

    Assert(keysize == sizeof(PREDICATELOCKTAG));

    /* Look into the associated target object, and compute its hash code */
    targethash = PredicateLockTargetTagHashCode(&predicatelocktag->myTarget->tag);

    return PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash);
}

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

Definition at line 4847 of file predicate.c.

References Assert, VirtualTransactionId::backendId, SERIALIZABLEXACT::commitSeqNo, CreatePredicateLock(), CreatePredXact(), TwoPhasePredicateRecord::data, ereport, errcode(), errmsg(), ERROR, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, TwoPhasePredicateXactRecord::flags, SERIALIZABLEXACT::flags, HASH_ENTER, HASH_FIND, hash_search(), SERIALIZABLEXACT::inConflicts, InvalidSerializableXact, 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, SERIALIZABLEXACT::SeqNo, SerializableXactHashLock, SHMQueueElemInit(), SHMQueueInit(), 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, TwoPhasePredicateXactRecord::xmin, and SERIALIZABLEXACT::xmin.

{
    TwoPhasePredicateRecord *record;

    Assert(len == sizeof(TwoPhasePredicateRecord));

    record = (TwoPhasePredicateRecord *) recdata;

    Assert((record->type == TWOPHASEPREDICATERECORD_XACT) ||
           (record->type == TWOPHASEPREDICATERECORD_LOCK));

    if (record->type == TWOPHASEPREDICATERECORD_XACT)
    {
        /* Per-transaction record. Set up a SERIALIZABLEXACT. */
        TwoPhasePredicateXactRecord *xactRecord;
        SERIALIZABLEXACT *sxact;
        SERIALIZABLEXID *sxid;
        SERIALIZABLEXIDTAG sxidtag;
        bool        found;

        xactRecord = (TwoPhasePredicateXactRecord *) &record->data.xactRecord;

        LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
        sxact = CreatePredXact();
        if (!sxact)
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of shared memory")));

        /* vxid for a prepared xact is InvalidBackendId/xid; no pid */
        sxact->vxid.backendId = InvalidBackendId;
        sxact->vxid.localTransactionId = (LocalTransactionId) xid;
        sxact->pid = 0;

        /* a prepared xact hasn't committed yet */
        sxact->prepareSeqNo = RecoverySerCommitSeqNo;
        sxact->commitSeqNo = InvalidSerCommitSeqNo;
        sxact->finishedBefore = InvalidTransactionId;

        sxact->SeqNo.lastCommitBeforeSnapshot = RecoverySerCommitSeqNo;

        /*
         * Don't need to track this; no transactions running at the time the
         * recovered xact started are still active, except possibly other
         * prepared xacts and we don't care whether those are RO_SAFE or not.
         */
        SHMQueueInit(&(sxact->possibleUnsafeConflicts));

        SHMQueueInit(&(sxact->predicateLocks));
        SHMQueueElemInit(&(sxact->finishedLink));

        sxact->topXid = xid;
        sxact->xmin = xactRecord->xmin;
        sxact->flags = xactRecord->flags;
        Assert(SxactIsPrepared(sxact));
        if (!SxactIsReadOnly(sxact))
        {
            ++(PredXact->WritableSxactCount);
            Assert(PredXact->WritableSxactCount <=
                   (MaxBackends + max_prepared_xacts));
        }

        /*
         * We don't know whether the transaction had any conflicts or not, so
         * we'll conservatively assume that it had both a conflict in and a
         * conflict out, and represent that with the summary conflict flags.
         */
        SHMQueueInit(&(sxact->outConflicts));
        SHMQueueInit(&(sxact->inConflicts));
        sxact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
        sxact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;

        /* Register the transaction's xid */
        sxidtag.xid = xid;
        sxid = (SERIALIZABLEXID *) hash_search(SerializableXidHash,
                                               &sxidtag,
                                               HASH_ENTER, &found);
        Assert(sxid != NULL);
        Assert(!found);
        sxid->myXact = (SERIALIZABLEXACT *) sxact;

        /*
         * Update global xmin. Note that this is a special case compared to
         * registering a normal transaction, because the global xmin might go
         * backwards. That's OK, because until recovery is over we're not
         * going to complete any transactions or create any non-prepared
         * transactions, so there's no danger of throwing away.
         */
        if ((!TransactionIdIsValid(PredXact->SxactGlobalXmin)) ||
            (TransactionIdFollows(PredXact->SxactGlobalXmin, sxact->xmin)))
        {
            PredXact->SxactGlobalXmin = sxact->xmin;
            PredXact->SxactGlobalXminCount = 1;
            OldSerXidSetActiveSerXmin(sxact->xmin);
        }
        else if (TransactionIdEquals(sxact->xmin, PredXact->SxactGlobalXmin))
        {
            Assert(PredXact->SxactGlobalXminCount > 0);
            PredXact->SxactGlobalXminCount++;
        }

        LWLockRelease(SerializableXactHashLock);
    }
    else if (record->type == TWOPHASEPREDICATERECORD_LOCK)
    {
        /* Lock record. Recreate the PREDICATELOCK */
        TwoPhasePredicateLockRecord *lockRecord;
        SERIALIZABLEXID *sxid;
        SERIALIZABLEXACT *sxact;
        SERIALIZABLEXIDTAG sxidtag;
        uint32      targettaghash;

        lockRecord = (TwoPhasePredicateLockRecord *) &record->data.lockRecord;
        targettaghash = PredicateLockTargetTagHashCode(&lockRecord->target);

        LWLockAcquire(SerializableXactHashLock, LW_SHARED);
        sxidtag.xid = xid;
        sxid = (SERIALIZABLEXID *)
            hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
        LWLockRelease(SerializableXactHashLock);

        Assert(sxid != NULL);
        sxact = sxid->myXact;
        Assert(sxact != InvalidSerializableXact);

        CreatePredicateLock(&lockRecord->target, targettaghash, sxact);
    }
}

static void PredicateLockAcquire ( const PREDICATELOCKTARGETTAG targettag  )  [static]

Definition at line 2358 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().

{
    uint32      targettaghash;
    bool        found;
    LOCALPREDICATELOCK *locallock;

    /* Do we have the lock already, or a covering lock? */
    if (PredicateLockExists(targettag))
        return;

    if (CoarserLockCovers(targettag))
        return;

    /* the same hash and LW lock apply to the lock target and the local lock. */
    targettaghash = PredicateLockTargetTagHashCode(targettag);

    /* Acquire lock in local table */
    locallock = (LOCALPREDICATELOCK *)
        hash_search_with_hash_value(LocalPredicateLockHash,
                                    targettag, targettaghash,
                                    HASH_ENTER, &found);
    locallock->held = true;
    if (!found)
        locallock->childLocks = 0;

    /* Actually create the lock */
    CreatePredicateLock(targettag, targettaghash, MySerializableXact);

    /*
     * Lock has been acquired. Check whether it should be promoted to a
     * coarser granularity, or whether there are finer-granularity locks to
     * clean up.
     */
    if (CheckAndPromotePredicateLockRequest(targettag))
    {
        /*
         * Lock request was promoted to a coarser-granularity lock, and that
         * lock was acquired. It will delete this lock and any of its
         * children, so we're done.
         */
    }
    else
    {
        /* Clean up any finer-granularity locks */
        if (GET_PREDICATELOCKTARGETTAG_TYPE(*targettag) != PREDLOCKTAG_TUPLE)
            DeleteChildTargetLocks(targettag);
    }
}

static bool PredicateLockExists ( const PREDICATELOCKTARGETTAG targettag  )  [static]

Definition at line 1892 of file predicate.c.

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

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

{
    LOCALPREDICATELOCK *lock;

    /* check local hash table */
    lock = (LOCALPREDICATELOCK *) hash_search(LocalPredicateLockHash,
                                              targettag,
                                              HASH_FIND, NULL);

    if (!lock)
        return false;

    /*
     * Found entry in the table, but still need to check whether it's actually
     * held -- it could just be a parent of some held lock.
     */
    return lock->held;
}

static bool PredicateLockingNeededForRelation ( Relation  relation  )  [inline, static]
void PredicateLockPage ( Relation  relation,
BlockNumber  blkno,
Snapshot  snapshot 
)
void PredicateLockPageCombine ( Relation  relation,
BlockNumber  oldblkno,
BlockNumber  newblkno 
)

Definition at line 3118 of file predicate.c.

References PredicateLockPageSplit().

Referenced by _bt_pagedel().

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

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

Definition at line 3033 of file predicate.c.

References Assert, BlockNumberIsValid, RelFileNode::dbNode, GetParentPredicateLockTag(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PredicateLockingNeededForRelation(), RelationData::rd_id, RelationData::rd_node, SerializablePredicateLockListLock, SET_PREDICATELOCKTARGETTAG_PAGE, PredXactListData::SxactGlobalXmin, TransactionIdIsValid, and TransferPredicateLocksToNewTarget().

Referenced by _bt_insertonpg(), and PredicateLockPageCombine().

{
    PREDICATELOCKTARGETTAG oldtargettag;
    PREDICATELOCKTARGETTAG newtargettag;
    bool        success;

    /*
     * Bail out quickly if there are no serializable transactions running.
     *
     * It's safe to do this check without taking any additional locks. Even if
     * a serializable transaction starts concurrently, we know it can't take
     * any SIREAD locks on the page being split because the caller is holding
     * the associated buffer page lock. Memory reordering isn't an issue; the
     * memory barrier in the LWLock acquisition guarantees that this read
     * occurs while the buffer page lock is held.
     */
    if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
        return;

    if (!PredicateLockingNeededForRelation(relation))
        return;

    Assert(oldblkno != newblkno);
    Assert(BlockNumberIsValid(oldblkno));
    Assert(BlockNumberIsValid(newblkno));

    SET_PREDICATELOCKTARGETTAG_PAGE(oldtargettag,
                                    relation->rd_node.dbNode,
                                    relation->rd_id,
                                    oldblkno);
    SET_PREDICATELOCKTARGETTAG_PAGE(newtargettag,
                                    relation->rd_node.dbNode,
                                    relation->rd_id,
                                    newblkno);

    LWLockAcquire(SerializablePredicateLockListLock, LW_EXCLUSIVE);

    /*
     * Try copying the locks over to the new page's tag, creating it if
     * necessary.
     */
    success = TransferPredicateLocksToNewTarget(oldtargettag,
                                                newtargettag,
                                                false);

    if (!success)
    {
        /*
         * No more predicate lock entries are available. Failure isn't an
         * option here, so promote the page lock to a relation lock.
         */

        /* Get the parent relation lock's lock tag */
        success = GetParentPredicateLockTag(&oldtargettag,
                                            &newtargettag);
        Assert(success);

        /*
         * Move the locks to the parent. This shouldn't fail.
         *
         * Note that here we are removing locks held by other backends,
         * leading to a possible inconsistency in their local lock hash table.
         * This is OK because we're replacing it with a lock that covers the
         * old one.
         */
        success = TransferPredicateLocksToNewTarget(oldtargettag,
                                                    newtargettag,
                                                    true);
        Assert(success);
    }

    LWLockRelease(SerializablePredicateLockListLock);
}

static int PredicateLockPromotionThreshold ( const PREDICATELOCKTARGETTAG tag  )  [static]

Definition at line 2136 of file predicate.c.

References Assert, GET_PREDICATELOCKTARGETTAG_TYPE, max_predicate_locks_per_xact, PREDLOCKTAG_PAGE, PREDLOCKTAG_RELATION, and PREDLOCKTAG_TUPLE.

Referenced by CheckAndPromotePredicateLockRequest().

{
    switch (GET_PREDICATELOCKTARGETTAG_TYPE(*tag))
    {
        case PREDLOCKTAG_RELATION:
            return max_predicate_locks_per_xact / 2;

        case PREDLOCKTAG_PAGE:
            return 3;

        case PREDLOCKTAG_TUPLE:

            /*
             * not reachable: nothing is finer-granularity than a tuple, so we
             * should never try to promote to it.
             */
            Assert(false);
            return 0;
    }

    /* not reachable */
    Assert(false);
    return 0;
}

void PredicateLockRelation ( Relation  relation,
Snapshot  snapshot 
)
Size PredicateLockShmemSize ( void   ) 

Definition at line 1297 of file predicate.c.

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

Referenced by CreateSharedMemoryAndSemaphores().

{
    Size        size = 0;
    long        max_table_size;

    /* predicate lock target hash table */
    max_table_size = NPREDICATELOCKTARGETENTS();
    size = add_size(size, hash_estimate_size(max_table_size,
                                             sizeof(PREDICATELOCKTARGET)));

    /* predicate lock hash table */
    max_table_size *= 2;
    size = add_size(size, hash_estimate_size(max_table_size,
                                             sizeof(PREDICATELOCK)));

    /*
     * Since NPREDICATELOCKTARGETENTS is only an estimate, add 10% safety
     * margin.
     */
    size = add_size(size, size / 10);

    /* transaction list */
    max_table_size = MaxBackends + max_prepared_xacts;
    max_table_size *= 10;
    size = add_size(size, PredXactListDataSize);
    size = add_size(size, mul_size((Size) max_table_size,
                                   PredXactListElementDataSize));

    /* transaction xid table */
    size = add_size(size, hash_estimate_size(max_table_size,
                                             sizeof(SERIALIZABLEXID)));

    /* rw-conflict pool */
    max_table_size *= 5;
    size = add_size(size, RWConflictPoolHeaderDataSize);
    size = add_size(size, mul_size((Size) max_table_size,
                                   RWConflictDataSize));

    /* Head for list of finished serializable transactions. */
    size = add_size(size, sizeof(SHM_QUEUE));

    /* Shared memory structures for SLRU tracking of old committed xids. */
    size = add_size(size, sizeof(OldSerXidControlData));
    size = add_size(size, SimpleLruShmemSize(NUM_OLDSERXID_BUFFERS, 0));

    return size;
}

void PredicateLockTuple ( Relation  relation,
HeapTuple  tuple,
Snapshot  snapshot 
)

Definition at line 2462 of file predicate.c.

References RelFileNode::dbNode, GetTopTransactionIdIfAny(), HeapTupleHeaderGetXmin, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, NULL, PredicateLockAcquire(), PredicateLockExists(), RelationData::rd_id, RelationData::rd_index, RelationData::rd_node, SerializationNeededForRead(), SET_PREDICATELOCKTARGETTAG_RELATION, SET_PREDICATELOCKTARGETTAG_TUPLE, SubTransGetTopmostTransaction(), HeapTupleData::t_data, HeapTupleData::t_self, TransactionIdEquals, TransactionIdFollowsOrEquals(), TransactionIdIsValid, and TransactionXmin.

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

{
    PREDICATELOCKTARGETTAG tag;
    ItemPointer tid;
    TransactionId targetxmin;

    if (!SerializationNeededForRead(relation, snapshot))
        return;

    /*
     * If it's a heap tuple, return if this xact wrote it.
     */
    if (relation->rd_index == NULL)
    {
        TransactionId myxid;

        targetxmin = HeapTupleHeaderGetXmin(tuple->t_data);

        myxid = GetTopTransactionIdIfAny();
        if (TransactionIdIsValid(myxid))
        {
            if (TransactionIdFollowsOrEquals(targetxmin, TransactionXmin))
            {
                TransactionId xid = SubTransGetTopmostTransaction(targetxmin);

                if (TransactionIdEquals(xid, myxid))
                {
                    /* We wrote it; we already have a write lock. */
                    return;
                }
            }
        }
    }
    else
        targetxmin = InvalidTransactionId;

    /*
     * Do quick-but-not-definitive test for a relation lock first.  This will
     * never cause a return when the relation is *not* locked, but will
     * occasionally let the check continue when there really *is* a relation
     * level lock.
     */
    SET_PREDICATELOCKTARGETTAG_RELATION(tag,
                                        relation->rd_node.dbNode,
                                        relation->rd_id);
    if (PredicateLockExists(&tag))
        return;

    tid = &(tuple->t_self);
    SET_PREDICATELOCKTARGETTAG_TUPLE(tag,
                                     relation->rd_node.dbNode,
                                     relation->rd_id,
                                     ItemPointerGetBlockNumber(tid),
                                     ItemPointerGetOffsetNumber(tid),
                                     targetxmin);
    PredicateLockAcquire(&tag);
}

void PredicateLockTwoPhaseFinish ( TransactionId  xid,
bool  isCommit 
)

Definition at line 4820 of file predicate.c.

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

Referenced by FinishPreparedTransaction().

{
    SERIALIZABLEXID *sxid;
    SERIALIZABLEXIDTAG sxidtag;

    sxidtag.xid = xid;

    LWLockAcquire(SerializableXactHashLock, LW_SHARED);
    sxid = (SERIALIZABLEXID *)
        hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
    LWLockRelease(SerializableXactHashLock);

    /* xid will not be found if it wasn't a serializable transaction */
    if (sxid == NULL)
        return;

    /* Release its locks */
    MySerializableXact = sxid->myXact;
    MyXactDidWrite = true;      /* conservatively assume that we wrote
                                 * something */
    ReleasePredicateLocks(isCommit);
}

void RegisterPredicateLockingXid ( TransactionId  xid  ) 

Definition at line 1806 of file predicate.c.

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

Referenced by AssignTransactionId().

{
    SERIALIZABLEXIDTAG sxidtag;
    SERIALIZABLEXID *sxid;
    bool        found;

    /*
     * If we're not tracking predicate lock data for this transaction, we
     * should ignore the request and return quickly.
     */
    if (MySerializableXact == InvalidSerializableXact)
        return;

    /* We should have a valid XID and be at the top level. */
    Assert(TransactionIdIsValid(xid));

    LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);

    /* This should only be done once per transaction. */
    Assert(MySerializableXact->topXid == InvalidTransactionId);

    MySerializableXact->topXid = xid;

    sxidtag.xid = xid;
    sxid = (SERIALIZABLEXID *) hash_search(SerializableXidHash,
                                           &sxidtag,
                                           HASH_ENTER, &found);
    Assert(!found);

    /* Initialize the structure. */
    sxid->myXact = MySerializableXact;
    LWLockRelease(SerializableXactHashLock);
}

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

Definition at line 3666 of file predicate.c.

References Assert, SERIALIZABLEXACT::commitSeqNo, PREDICATELOCK::commitSeqNo, ereport, errcode(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::flags, HASH_ENTER_NULL, HASH_REMOVE, hash_search(), hash_search_with_hash_value(), SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, InvalidSerCommitSeqNo, InvalidTransactionId, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, NULL, offsetof, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, PREDICATELOCKTARGET::predicateLocks, SERIALIZABLEXACT::predicateLocks, PredicateLockTargetTagHashCode, ReleasePredXact(), ReleaseRWConflict(), RemoveTargetIfNoLongerUsed(), SerializableFinishedListLock, SerializablePredicateLockListLock, SerializableXactHashLock, SHMQueueDelete(), SHMQueueInit(), SHMQueueInsertBefore(), SHMQueueNext(), RWConflictData::sxactIn, SxactIsCommitted, SxactIsOnFinishedList, SxactIsRolledBack, RWConflictData::sxactOut, PREDICATELOCKTARGET::tag, PREDICATELOCK::tag, PREDICATELOCK::targetLink, SERIALIZABLEXACT::topXid, PREDICATELOCK::xactLink, and SERIALIZABLEXIDTAG::xid.

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

{
    PREDICATELOCK *predlock;
    SERIALIZABLEXIDTAG sxidtag;
    RWConflict  conflict,
                nextConflict;

    Assert(sxact != NULL);
    Assert(SxactIsRolledBack(sxact) || SxactIsCommitted(sxact));
    Assert(partial || !SxactIsOnFinishedList(sxact));
    Assert(LWLockHeldByMe(SerializableFinishedListLock));

    /*
     * First release all the predicate locks held by this xact (or transfer
     * them to OldCommittedSxact if summarize is true)
     */
    LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
    predlock = (PREDICATELOCK *)
        SHMQueueNext(&(sxact->predicateLocks),
                     &(sxact->predicateLocks),
                     offsetof(PREDICATELOCK, xactLink));
    while (predlock)
    {
        PREDICATELOCK *nextpredlock;
        PREDICATELOCKTAG tag;
        SHM_QUEUE  *targetLink;
        PREDICATELOCKTARGET *target;
        PREDICATELOCKTARGETTAG targettag;
        uint32      targettaghash;
        LWLockId    partitionLock;

        nextpredlock = (PREDICATELOCK *)
            SHMQueueNext(&(sxact->predicateLocks),
                         &(predlock->xactLink),
                         offsetof(PREDICATELOCK, xactLink));

        tag = predlock->tag;
        targetLink = &(predlock->targetLink);
        target = tag.myTarget;
        targettag = target->tag;
        targettaghash = PredicateLockTargetTagHashCode(&targettag);
        partitionLock = PredicateLockHashPartitionLock(targettaghash);

        LWLockAcquire(partitionLock, LW_EXCLUSIVE);

        SHMQueueDelete(targetLink);

        hash_search_with_hash_value(PredicateLockHash, &tag,
                                PredicateLockHashCodeFromTargetHashCode(&tag,
                                                              targettaghash),
                                    HASH_REMOVE, NULL);
        if (summarize)
        {
            bool        found;

            /* Fold into dummy transaction list. */
            tag.myXact = OldCommittedSxact;
            predlock = hash_search_with_hash_value(PredicateLockHash, &tag,
                                PredicateLockHashCodeFromTargetHashCode(&tag,
                                                              targettaghash),
                                                   HASH_ENTER_NULL, &found);
            if (!predlock)
                ereport(ERROR,
                        (errcode(ERRCODE_OUT_OF_MEMORY),
                         errmsg("out of shared memory"),
                         errhint("You might need to increase max_pred_locks_per_transaction.")));
            if (found)
            {
                Assert(predlock->commitSeqNo != 0);
                Assert(predlock->commitSeqNo != InvalidSerCommitSeqNo);
                if (predlock->commitSeqNo < sxact->commitSeqNo)
                    predlock->commitSeqNo = sxact->commitSeqNo;
            }
            else
            {
                SHMQueueInsertBefore(&(target->predicateLocks),
                                     &(predlock->targetLink));
                SHMQueueInsertBefore(&(OldCommittedSxact->predicateLocks),
                                     &(predlock->xactLink));
                predlock->commitSeqNo = sxact->commitSeqNo;
            }
        }
        else
            RemoveTargetIfNoLongerUsed(target, targettaghash);

        LWLockRelease(partitionLock);

        predlock = nextpredlock;
    }

    /*
     * Rather than retail removal, just re-init the head after we've run
     * through the list.
     */
    SHMQueueInit(&sxact->predicateLocks);

    LWLockRelease(SerializablePredicateLockListLock);

    sxidtag.xid = sxact->topXid;
    LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);

    /* Release all outConflicts (unless 'partial' is true) */
    if (!partial)
    {
        conflict = (RWConflict)
            SHMQueueNext(&sxact->outConflicts,
                         &sxact->outConflicts,
                         offsetof(RWConflictData, outLink));
        while (conflict)
        {
            nextConflict = (RWConflict)
                SHMQueueNext(&sxact->outConflicts,
                             &conflict->outLink,
                             offsetof(RWConflictData, outLink));
            if (summarize)
                conflict->sxactIn->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
            ReleaseRWConflict(conflict);
            conflict = nextConflict;
        }
    }

    /* Release all inConflicts. */
    conflict = (RWConflict)
        SHMQueueNext(&sxact->inConflicts,
                     &sxact->inConflicts,
                     offsetof(RWConflictData, inLink));
    while (conflict)
    {
        nextConflict = (RWConflict)
            SHMQueueNext(&sxact->inConflicts,
                         &conflict->inLink,
                         offsetof(RWConflictData, inLink));
        if (summarize)
            conflict->sxactOut->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
        ReleaseRWConflict(conflict);
        conflict = nextConflict;
    }

    /* Finally, get rid of the xid and the record of the transaction itself. */
    if (!partial)
    {
        if (sxidtag.xid != InvalidTransactionId)
            hash_search(SerializableXidHash, &sxidtag, HASH_REMOVE, NULL);
        ReleasePredXact(sxact);
    }

    LWLockRelease(SerializableXactHashLock);
}

void ReleasePredicateLocks ( bool  isCommit  ) 

Definition at line 3190 of file predicate.c.

References Assert, PredXactListData::CanPartialClearThrough, ClearOldPredicateLocks(), SERIALIZABLEXACT::commitSeqNo, SERIALIZABLEXACT::earliestOutConflictCommit, SERIALIZABLEXACT::finishedBefore, SERIALIZABLEXACT::finishedLink, SERIALIZABLEXACT::flags, FlagSxactUnsafe(), hash_destroy(), SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, InvalidSerializableXact, IsolationIsSerializable, SERIALIZABLEXACT::lastCommitBeforeSnapshot, PredXactListData::LastSxactCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyXactDidWrite, VariableCacheData::nextXid, NULL, offsetof, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SERIALIZABLEXACT::pid, SERIALIZABLEXACT::possibleUnsafeConflicts, SERIALIZABLEXACT::prepareSeqNo, ProcSendSignal(), ReleaseOneSerializableXact(), ReleaseRWConflict(), SERIALIZABLEXACT::SeqNo, SerializableFinishedListLock, SerializableXactHashLock, SetNewSxactGlobalXmin(), ShmemVariableCache, SHMQueueEmpty(), SHMQueueInsertBefore(), SHMQueueNext(), SXACT_FLAG_CONFLICT_OUT, PredXactListData::SxactGlobalXmin, PredXactListData::SxactGlobalXminCount, SxactHasConflictOut, SxactHasSummaryConflictOut, RWConflictData::sxactIn, SxactIsCommitted, SxactIsDeferrableWaiting, SxactIsDoomed, SxactIsOnFinishedList, SxactIsPrepared, SxactIsReadOnly, SxactIsRolledBack, SxactIsROSafe, SxactIsROUnsafe, RWConflictData::sxactOut, TransactionIdEquals, PredXactListData::WritableSxactCount, and SERIALIZABLEXACT::xmin.

Referenced by GetSafeSnapshot(), PredicateLockTwoPhaseFinish(), ResourceOwnerReleaseInternal(), and SerializationNeededForRead().

{
    bool        needToClear;
    RWConflict  conflict,
                nextConflict,
                possibleUnsafeConflict;
    SERIALIZABLEXACT *roXact;

    /*
     * We can't trust XactReadOnly here, because a transaction which started
     * as READ WRITE can show as READ ONLY later, e.g., within
     * substransactions.  We want to flag a transaction as READ ONLY if it
     * commits without writing so that de facto READ ONLY transactions get the
     * benefit of some RO optimizations, so we will use this local variable to
     * get some cleanup logic right which is based on whether the transaction
     * was declared READ ONLY at the top level.
     */
    bool        topLevelIsDeclaredReadOnly;

    if (MySerializableXact == InvalidSerializableXact)
    {
        Assert(LocalPredicateLockHash == NULL);
        return;
    }

    Assert(!isCommit || SxactIsPrepared(MySerializableXact));
    Assert(!isCommit || !SxactIsDoomed(MySerializableXact));
    Assert(!SxactIsCommitted(MySerializableXact));
    Assert(!SxactIsRolledBack(MySerializableXact));

    /* may not be serializable during COMMIT/ROLLBACK PREPARED */
    if (MySerializableXact->pid != 0)
        Assert(IsolationIsSerializable());

    /* We'd better not already be on the cleanup list. */
    Assert(!SxactIsOnFinishedList(MySerializableXact));

    topLevelIsDeclaredReadOnly = SxactIsReadOnly(MySerializableXact);

    LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);

    /*
     * We don't hold XidGenLock lock here, assuming that TransactionId is
     * atomic!
     *
     * If this value is changing, we don't care that much whether we get the
     * old or new value -- it is just used to determine how far
     * GlobalSerizableXmin must advance before this transaction can be fully
     * cleaned up.  The worst that could happen is we wait for one more
     * transaction to complete before freeing some RAM; correctness of visible
     * behavior is not affected.
     */
    MySerializableXact->finishedBefore = ShmemVariableCache->nextXid;

    /*
     * If it's not a commit it's a rollback, and we can clear our locks
     * immediately.
     */
    if (isCommit)
    {
        MySerializableXact->flags |= SXACT_FLAG_COMMITTED;
        MySerializableXact->commitSeqNo = ++(PredXact->LastSxactCommitSeqNo);
        /* Recognize implicit read-only transaction (commit without write). */
        if (!MyXactDidWrite)
            MySerializableXact->flags |= SXACT_FLAG_READ_ONLY;
    }
    else
    {
        /*
         * The DOOMED flag indicates that we intend to roll back this
         * transaction and so it should not cause serialization failures for
         * other transactions that conflict with it. Note that this flag might
         * already be set, if another backend marked this transaction for
         * abort.
         *
         * The ROLLED_BACK flag further indicates that ReleasePredicateLocks
         * has been called, and so the SerializableXact is eligible for
         * cleanup. This means it should not be considered when calculating
         * SxactGlobalXmin.
         */
        MySerializableXact->flags |= SXACT_FLAG_DOOMED;
        MySerializableXact->flags |= SXACT_FLAG_ROLLED_BACK;

        /*
         * If the transaction was previously prepared, but is now failing due
         * to a ROLLBACK PREPARED or (hopefully very rare) error after the
         * prepare, clear the prepared flag.  This simplifies conflict
         * checking.
         */
        MySerializableXact->flags &= ~SXACT_FLAG_PREPARED;
    }

    if (!topLevelIsDeclaredReadOnly)
    {
        Assert(PredXact->WritableSxactCount > 0);
        if (--(PredXact->WritableSxactCount) == 0)
        {
            /*
             * Release predicate locks and rw-conflicts in for all committed
             * transactions.  There are no longer any transactions which might
             * conflict with the locks and no chance for new transactions to
             * overlap.  Similarly, existing conflicts in can't cause pivots,
             * and any conflicts in which could have completed a dangerous
             * structure would already have caused a rollback, so any
             * remaining ones must be benign.
             */
            PredXact->CanPartialClearThrough = PredXact->LastSxactCommitSeqNo;
        }
    }
    else
    {
        /*
         * Read-only transactions: clear the list of transactions that might
         * make us unsafe. Note that we use 'inLink' for the iteration as
         * opposed to 'outLink' for the r/w xacts.
         */
        possibleUnsafeConflict = (RWConflict)
            SHMQueueNext(&MySerializableXact->possibleUnsafeConflicts,
                         &MySerializableXact->possibleUnsafeConflicts,
                         offsetof(RWConflictData, inLink));
        while (possibleUnsafeConflict)
        {
            nextConflict = (RWConflict)
                SHMQueueNext(&MySerializableXact->possibleUnsafeConflicts,
                             &possibleUnsafeConflict->inLink,
                             offsetof(RWConflictData, inLink));

            Assert(!SxactIsReadOnly(possibleUnsafeConflict->sxactOut));
            Assert(MySerializableXact == possibleUnsafeConflict->sxactIn);

            ReleaseRWConflict(possibleUnsafeConflict);

            possibleUnsafeConflict = nextConflict;
        }
    }

    /* Check for conflict out to old committed transactions. */
    if (isCommit
        && !SxactIsReadOnly(MySerializableXact)
        && SxactHasSummaryConflictOut(MySerializableXact))
    {
        /*
         * we don't know which old committed transaction we conflicted with,
         * so be conservative and use FirstNormalSerCommitSeqNo here
         */
        MySerializableXact->SeqNo.earliestOutConflictCommit =
            FirstNormalSerCommitSeqNo;
        MySerializableXact->flags |= SXACT_FLAG_CONFLICT_OUT;
    }

    /*
     * Release all outConflicts to committed transactions.  If we're rolling
     * back clear them all.  Set SXACT_FLAG_CONFLICT_OUT if any point to
     * previously committed transactions.
     */
    conflict = (RWConflict)
        SHMQueueNext(&MySerializableXact->outConflicts,
                     &MySerializableXact->outConflicts,
                     offsetof(RWConflictData, outLink));
    while (conflict)
    {
        nextConflict = (RWConflict)
            SHMQueueNext(&MySerializableXact->outConflicts,
                         &conflict->outLink,
                         offsetof(RWConflictData, outLink));

        if (isCommit
            && !SxactIsReadOnly(MySerializableXact)
            && SxactIsCommitted(conflict->sxactIn))
        {
            if ((MySerializableXact->flags & SXACT_FLAG_CONFLICT_OUT) == 0
                || conflict->sxactIn->prepareSeqNo < MySerializableXact->SeqNo.earliestOutConflictCommit)
                MySerializableXact->SeqNo.earliestOutConflictCommit = conflict->sxactIn->prepareSeqNo;
            MySerializableXact->flags |= SXACT_FLAG_CONFLICT_OUT;
        }

        if (!isCommit
            || SxactIsCommitted(conflict->sxactIn)
            || (conflict->sxactIn->SeqNo.lastCommitBeforeSnapshot >= PredXact->LastSxactCommitSeqNo))
            ReleaseRWConflict(conflict);

        conflict = nextConflict;
    }

    /*
     * Release all inConflicts from committed and read-only transactions. If
     * we're rolling back, clear them all.
     */
    conflict = (RWConflict)
        SHMQueueNext(&MySerializableXact->inConflicts,
                     &MySerializableXact->inConflicts,
                     offsetof(RWConflictData, inLink));
    while (conflict)
    {
        nextConflict = (RWConflict)
            SHMQueueNext(&MySerializableXact->inConflicts,
                         &conflict->inLink,
                         offsetof(RWConflictData, inLink));

        if (!isCommit
            || SxactIsCommitted(conflict->sxactOut)
            || SxactIsReadOnly(conflict->sxactOut))
            ReleaseRWConflict(conflict);

        conflict = nextConflict;
    }

    if (!topLevelIsDeclaredReadOnly)
    {
        /*
         * Remove ourselves from the list of possible conflicts for concurrent
         * READ ONLY transactions, flagging them as unsafe if we have a
         * conflict out. If any are waiting DEFERRABLE transactions, wake them
         * up if they are known safe or known unsafe.
         */
        possibleUnsafeConflict = (RWConflict)
            SHMQueueNext(&MySerializableXact->possibleUnsafeConflicts,
                         &MySerializableXact->possibleUnsafeConflicts,
                         offsetof(RWConflictData, outLink));
        while (possibleUnsafeConflict)
        {
            nextConflict = (RWConflict)
                SHMQueueNext(&MySerializableXact->possibleUnsafeConflicts,
                             &possibleUnsafeConflict->outLink,
                             offsetof(RWConflictData, outLink));

            roXact = possibleUnsafeConflict->sxactIn;
            Assert(MySerializableXact == possibleUnsafeConflict->sxactOut);
            Assert(SxactIsReadOnly(roXact));

            /* Mark conflicted if necessary. */
            if (isCommit
                && MyXactDidWrite
                && SxactHasConflictOut(MySerializableXact)
                && (MySerializableXact->SeqNo.earliestOutConflictCommit
                    <= roXact->SeqNo.lastCommitBeforeSnapshot))
            {
                /*
                 * This releases possibleUnsafeConflict (as well as all other
                 * possible conflicts for roXact)
                 */
                FlagSxactUnsafe(roXact);
            }
            else
            {
                ReleaseRWConflict(possibleUnsafeConflict);

                /*
                 * If we were the last possible conflict, flag it safe. The
                 * transaction can now safely release its predicate locks (but
                 * that transaction's backend has to do that itself).
                 */
                if (SHMQueueEmpty(&roXact->possibleUnsafeConflicts))
                    roXact->flags |= SXACT_FLAG_RO_SAFE;
            }

            /*
             * Wake up the process for a waiting DEFERRABLE transaction if we
             * now know it's either safe or conflicted.
             */
            if (SxactIsDeferrableWaiting(roXact) &&
                (SxactIsROUnsafe(roXact) || SxactIsROSafe(roXact)))
                ProcSendSignal(roXact->pid);

            possibleUnsafeConflict = nextConflict;
        }
    }

    /*
     * Check whether it's time to clean up old transactions. This can only be
     * done when the last serializable transaction with the oldest xmin among
     * serializable transactions completes.  We then find the "new oldest"
     * xmin and purge any transactions which finished before this transaction
     * was launched.
     */
    needToClear = false;
    if (TransactionIdEquals(MySerializableXact->xmin, PredXact->SxactGlobalXmin))
    {
        Assert(PredXact->SxactGlobalXminCount > 0);
        if (--(PredXact->SxactGlobalXminCount) == 0)
        {
            SetNewSxactGlobalXmin();
            needToClear = true;
        }
    }

    LWLockRelease(SerializableXactHashLock);

    LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);

    /* Add this to the list of transactions to check for later cleanup. */
    if (isCommit)
        SHMQueueInsertBefore(FinishedSerializableTransactions,
                             &MySerializableXact->finishedLink);

    if (!isCommit)
        ReleaseOneSerializableXact(MySerializableXact, false, false);

    LWLockRelease(SerializableFinishedListLock);

    if (needToClear)
        ClearOldPredicateLocks();

    MySerializableXact = InvalidSerializableXact;
    MyXactDidWrite = false;

    /* Delete per-transaction lock table */
    if (LocalPredicateLockHash != NULL)
    {
        hash_destroy(LocalPredicateLockHash);
        LocalPredicateLockHash = NULL;
    }
}

static void ReleasePredXact ( SERIALIZABLEXACT sxact  )  [static]
static void ReleaseRWConflict ( RWConflict  conflict  )  [static]
static void RemoveScratchTarget ( bool  lockheld  )  [static]
static void RemoveTargetIfNoLongerUsed ( PREDICATELOCKTARGET target,
uint32  targettaghash 
) [static]
static void RestoreScratchTarget ( bool  lockheld  )  [static]
static bool RWConflictExists ( const SERIALIZABLEXACT reader,
const SERIALIZABLEXACT writer 
) [static]

Definition at line 624 of file predicate.c.

References Assert, SERIALIZABLEXACT::inConflicts, offsetof, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, SHMQueueEmpty(), SHMQueueNext(), RWConflictData::sxactIn, and SxactIsDoomed.

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

{
    RWConflict  conflict;

    Assert(reader != writer);

    /* Check the ends of the purported conflict first. */
    if (SxactIsDoomed(reader)
        || SxactIsDoomed(writer)
        || SHMQueueEmpty(&reader->outConflicts)
        || SHMQueueEmpty(&writer->inConflicts))
        return false;

    /* A conflict is possible; walk the list to find out. */
    conflict = (RWConflict)
        SHMQueueNext(&reader->outConflicts,
                     &reader->outConflicts,
                     offsetof(RWConflictData, outLink));
    while (conflict)
    {
        if (conflict->sxactIn == writer)
            return true;
        conflict = (RWConflict)
            SHMQueueNext(&reader->outConflicts,
                         &conflict->outLink,
                         offsetof(RWConflictData, outLink));
    }

    /* No conflict found. */
    return false;
}

static bool SerializationNeededForRead ( Relation  relation,
Snapshot  snapshot 
) [inline, static]

Definition at line 485 of file predicate.c.

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

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

{
    /* Nothing to do if this is not a serializable transaction */
    if (MySerializableXact == InvalidSerializableXact)
        return false;

    /*
     * Don't acquire locks or conflict when scanning with a special snapshot.
     * This excludes things like CLUSTER and REINDEX. They use the wholesale
     * functions TransferPredicateLocksToHeapRelation() and
     * CheckTableForSerializableConflictIn() to participate serialization, but
     * the scans involved don't need serialization.
     */
    if (!IsMVCCSnapshot(snapshot))
        return false;

    /*
     * Check if we have just become "RO-safe". If we have, immediately release
     * all locks as they're not needed anymore. This also resets
     * MySerializableXact, so that subsequent calls to this function can exit
     * quickly.
     *
     * A transaction is flagged as RO_SAFE if all concurrent R/W transactions
     * commit without having conflicts out to an earlier snapshot, thus
     * ensuring that no conflicts are possible for this transaction.
     */
    if (SxactIsROSafe(MySerializableXact))
    {
        ReleasePredicateLocks(false);
        return false;
    }

    /* Check if the relation doesn't participate in predicate locking */
    if (!PredicateLockingNeededForRelation(relation))
        return false;

    return true;                /* no excuse to skip predicate locking */
}

static bool SerializationNeededForWrite ( Relation  relation  )  [inline, static]

Definition at line 529 of file predicate.c.

References InvalidSerializableXact, and PredicateLockingNeededForRelation().

Referenced by CheckForSerializableConflictIn(), and CheckTableForSerializableConflictIn().

{
    /* Nothing to do if this is not a serializable transaction */
    if (MySerializableXact == InvalidSerializableXact)
        return false;

    /* Check if the relation doesn't participate in predicate locking */
    if (!PredicateLockingNeededForRelation(relation))
        return false;

    return true;                /* no excuse to skip predicate locking */
}

static void SetNewSxactGlobalXmin ( void   )  [static]
static void SetPossibleUnsafeConflict ( SERIALIZABLEXACT roXact,
SERIALIZABLEXACT activeXact 
) [static]

Definition at line 683 of file predicate.c.

References Assert, RWConflictPoolHeaderData::availableList, ereport, errcode(), errhint(), errmsg(), ERROR, RWConflictData::inLink, offsetof, RWConflictData::outLink, SERIALIZABLEXACT::possibleUnsafeConflicts, SHMQueueDelete(), SHMQueueInsertBefore(), SHMQueueNext(), RWConflictData::sxactIn, SxactIsReadOnly, and RWConflictData::sxactOut.

Referenced by GetSerializableTransactionSnapshotInt().

{
    RWConflict  conflict;

    Assert(roXact != activeXact);
    Assert(SxactIsReadOnly(roXact));
    Assert(!SxactIsReadOnly(activeXact));

    conflict = (RWConflict)
        SHMQueueNext(&RWConflictPool->availableList,
                     &RWConflictPool->availableList,
                     offsetof(RWConflictData, outLink));
    if (!conflict)
        ereport(ERROR,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("not enough elements in RWConflictPool to record a potential read/write conflict"),
                 errhint("You might need to run fewer transactions at a time or increase max_connections.")));

    SHMQueueDelete(&conflict->outLink);

    conflict->sxactOut = activeXact;
    conflict->sxactIn = roXact;
    SHMQueueInsertBefore(&activeXact->possibleUnsafeConflicts,
                         &conflict->outLink);
    SHMQueueInsertBefore(&roXact->possibleUnsafeConflicts,
                         &conflict->inLink);
}

static void SetRWConflict ( SERIALIZABLEXACT reader,
SERIALIZABLEXACT writer 
) [static]

Definition at line 657 of file predicate.c.

References Assert, RWConflictPoolHeaderData::availableList, ereport, errcode(), errhint(), errmsg(), ERROR, SERIALIZABLEXACT::inConflicts, RWConflictData::inLink, offsetof, SERIALIZABLEXACT::outConflicts, RWConflictData::outLink, RWConflictExists(), SHMQueueDelete(), SHMQueueInsertBefore(), SHMQueueNext(), RWConflictData::sxactIn, and RWConflictData::sxactOut.

Referenced by FlagRWConflict().

{
    RWConflict  conflict;

    Assert(reader != writer);
    Assert(!RWConflictExists(reader, writer));

    conflict = (RWConflict)
        SHMQueueNext(&RWConflictPool->availableList,
                     &RWConflictPool->availableList,
                     offsetof(RWConflictData, outLink));
    if (!conflict)
        ereport(ERROR,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("not enough elements in RWConflictPool to record a read/write conflict"),
                 errhint("You might need to run fewer transactions at a time or increase max_connections.")));

    SHMQueueDelete(&conflict->outLink);

    conflict->sxactOut = reader;
    conflict->sxactIn = writer;
    SHMQueueInsertBefore(&reader->outConflicts, &conflict->outLink);
    SHMQueueInsertBefore(&writer->inConflicts, &conflict->inLink);
}

void SetSerializableTransactionSnapshot ( Snapshot  snapshot,
TransactionId  sourcexid 
)

Definition at line 1612 of file predicate.c.

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

Referenced by SetTransactionSnapshot().

{
    Assert(IsolationIsSerializable());

    /*
     * We do not allow SERIALIZABLE READ ONLY DEFERRABLE transactions to
     * import snapshots, since there's no way to wait for a safe snapshot when
     * we're using the snap we're told to.  (XXX instead of throwing an error,
     * we could just ignore the XactDeferrable flag?)
     */
    if (XactReadOnly && XactDeferrable)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("a snapshot-importing transaction must not be READ ONLY DEFERRABLE")));

    (void) GetSerializableTransactionSnapshotInt(snapshot, sourcexid);
}

static void SummarizeOldestCommittedSxact ( void   )  [static]

Definition at line 1443 of file predicate.c.

References SERIALIZABLEXACT::earliestOutConflictCommit, SERIALIZABLEXACT::finishedLink, InvalidSerCommitSeqNo, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), offsetof, OldSerXidAdd(), ReleaseOneSerializableXact(), SERIALIZABLEXACT::SeqNo, SerializableFinishedListLock, SHMQueueDelete(), SHMQueueEmpty(), SHMQueueNext(), SxactHasConflictOut, SxactIsReadOnly, SERIALIZABLEXACT::topXid, and TransactionIdIsValid.

Referenced by GetSerializableTransactionSnapshotInt().

{
    SERIALIZABLEXACT *sxact;

    LWLockAcquire(SerializableFinishedListLock, LW_EXCLUSIVE);

    /*
     * This function is only called if there are no sxact slots available.
     * Some of them must belong to old, already-finished transactions, so
     * there should be something in FinishedSerializableTransactions list that
     * we can summarize. However, there's a race condition: while we were not
     * holding any locks, a transaction might have ended and cleaned up all
     * the finished sxact entries already, freeing up their sxact slots. In
     * that case, we have nothing to do here. The caller will find one of the
     * slots released by the other backend when it retries.
     */
    if (SHMQueueEmpty(FinishedSerializableTransactions))
    {
        LWLockRelease(SerializableFinishedListLock);
        return;
    }

    /*
     * Grab the first sxact off the finished list -- this will be the earliest
     * commit.  Remove it from the list.
     */
    sxact = (SERIALIZABLEXACT *)
        SHMQueueNext(FinishedSerializableTransactions,
                     FinishedSerializableTransactions,
                     offsetof(SERIALIZABLEXACT, finishedLink));
    SHMQueueDelete(&(sxact->finishedLink));

    /* Add to SLRU summary information. */
    if (TransactionIdIsValid(sxact->topXid) && !SxactIsReadOnly(sxact))
        OldSerXidAdd(sxact->topXid, SxactHasConflictOut(sxact)
           ? sxact->SeqNo.earliestOutConflictCommit : InvalidSerCommitSeqNo);

    /* Summarize and release the detail. */
    ReleaseOneSerializableXact(sxact, false, true);

    LWLockRelease(SerializableFinishedListLock);
}

void TransferPredicateLocksToHeapRelation ( Relation  relation  ) 

Definition at line 3012 of file predicate.c.

References DropAllPredicateLocksFromTable().

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

{
    DropAllPredicateLocksFromTable(relation, true);
}

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

Definition at line 2600 of file predicate.c.

References Assert, PREDICATELOCK::commitSeqNo, DeleteLockTarget(), HASH_ENTER_NULL, HASH_FIND, HASH_REMOVE, hash_search_with_hash_value(), InvalidSerCommitSeqNo, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), PREDICATELOCKTAG::myTarget, PREDICATELOCKTAG::myXact, NULL, offsetof, PredicateLockHashCodeFromTargetHashCode, PredicateLockHashPartitionLock, SERIALIZABLEXACT::predicateLocks, PREDICATELOCKTARGET::predicateLocks, PredicateLockTargetTagHashCode, RemoveScratchTarget(), RemoveTargetIfNoLongerUsed(), RestoreScratchTarget(), SerializablePredicateLockListLock, SerializableXactHashLock, SHMQueueDelete(), SHMQueueEmpty(), SHMQueueInit(), SHMQueueInsertBefore(), SHMQueueNext(), PREDICATELOCK::tag, PREDICATELOCK::targetLink, and PREDICATELOCK::xactLink.

Referenced by PredicateLockPageSplit().

{
    uint32      oldtargettaghash;
    LWLockId    oldpartitionLock;
    PREDICATELOCKTARGET *oldtarget;
    uint32      newtargettaghash;
    LWLockId    newpartitionLock;
    bool        found;
    bool        outOfShmem = false;

    Assert(LWLockHeldByMe(SerializablePredicateLockListLock));

    oldtargettaghash = PredicateLockTargetTagHashCode(&oldtargettag);
    newtargettaghash = PredicateLockTargetTagHashCode(&newtargettag);
    oldpartitionLock = PredicateLockHashPartitionLock(oldtargettaghash);
    newpartitionLock = PredicateLockHashPartitionLock(newtargettaghash);

    if (removeOld)
    {
        /*
         * Remove the dummy entry to give us scratch space, so we know we'll
         * be able to create the new lock target.
         */
        RemoveScratchTarget(false);
    }

    /*
     * We must get the partition locks in ascending sequence to avoid
     * deadlocks. If old and new partitions are the same, we must request the
     * lock only once.
     */
    if (oldpartitionLock < newpartitionLock)
    {
        LWLockAcquire(oldpartitionLock,
                      (removeOld ? LW_EXCLUSIVE : LW_SHARED));
        LWLockAcquire(newpartitionLock, LW_EXCLUSIVE);
    }
    else if (oldpartitionLock > newpartitionLock)
    {
        LWLockAcquire(newpartitionLock, LW_EXCLUSIVE);
        LWLockAcquire(oldpartitionLock,
                      (removeOld ? LW_EXCLUSIVE : LW_SHARED));
    }
    else
        LWLockAcquire(newpartitionLock, LW_EXCLUSIVE);

    /*
     * Look for the old target.  If not found, that's OK; no predicate locks
     * are affected, so we can just clean up and return. If it does exist,
     * walk its list of predicate locks and move or copy them to the new
     * target.
     */
    oldtarget = hash_search_with_hash_value(PredicateLockTargetHash,
                                            &oldtargettag,
                                            oldtargettaghash,
                                            HASH_FIND, NULL);

    if (oldtarget)
    {
        PREDICATELOCKTARGET *newtarget;
        PREDICATELOCK *oldpredlock;
        PREDICATELOCKTAG newpredlocktag;

        newtarget = hash_search_with_hash_value(PredicateLockTargetHash,
                                                &newtargettag,
                                                newtargettaghash,
                                                HASH_ENTER_NULL, &found);

        if (!newtarget)
        {
            /* Failed to allocate due to insufficient shmem */
            outOfShmem = true;
            goto exit;
        }

        /* If we created a new entry, initialize it */
        if (!found)
            SHMQueueInit(&(newtarget->predicateLocks));

        newpredlocktag.myTarget = newtarget;

        /*
         * Loop through all the locks on the old target, replacing them with
         * locks on the new target.
         */
        oldpredlock = (PREDICATELOCK *)
            SHMQueueNext(&(oldtarget->predicateLocks),
                         &(oldtarget->predicateLocks),
                         offsetof(PREDICATELOCK, targetLink));
        LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
        while (oldpredlock)
        {
            SHM_QUEUE  *predlocktargetlink;
            PREDICATELOCK *nextpredlock;
            PREDICATELOCK *newpredlock;
            SerCommitSeqNo oldCommitSeqNo = oldpredlock->commitSeqNo;

            predlocktargetlink = &(oldpredlock->targetLink);
            nextpredlock = (PREDICATELOCK *)
                SHMQueueNext(&(oldtarget->predicateLocks),
                             predlocktargetlink,
                             offsetof(PREDICATELOCK, targetLink));
            newpredlocktag.myXact = oldpredlock->tag.myXact;

            if (removeOld)
            {
                SHMQueueDelete(&(oldpredlock->xactLink));
                SHMQueueDelete(&(oldpredlock->targetLink));

                hash_search_with_hash_value
                    (PredicateLockHash,
                     &oldpredlock->tag,
                   PredicateLockHashCodeFromTargetHashCode(&oldpredlock->tag,
                                                           oldtargettaghash),
                     HASH_REMOVE, &found);
                Assert(found);
            }

            newpredlock = (PREDICATELOCK *)
                hash_search_with_hash_value(PredicateLockHash,
                                            &newpredlocktag,
                     PredicateLockHashCodeFromTargetHashCode(&newpredlocktag,
                                                           newtargettaghash),
                                            HASH_ENTER_NULL,
                                            &found);
            if (!newpredlock)
            {
                /* Out of shared memory. Undo what we've done so far. */
                LWLockRelease(SerializableXactHashLock);
                DeleteLockTarget(newtarget, newtargettaghash);
                outOfShmem = true;
                goto exit;
            }
            if (!found)
            {
                SHMQueueInsertBefore(&(newtarget->predicateLocks),
                                     &(newpredlock->targetLink));
                SHMQueueInsertBefore(&(newpredlocktag.myXact->predicateLocks),
                                     &(newpredlock->xactLink));
                newpredlock->commitSeqNo = oldCommitSeqNo;
            }
            else
            {
                if (newpredlock->commitSeqNo < oldCommitSeqNo)
                    newpredlock->commitSeqNo = oldCommitSeqNo;
            }

            Assert(newpredlock->commitSeqNo != 0);
            Assert((newpredlock->commitSeqNo == InvalidSerCommitSeqNo)
                   || (newpredlock->tag.myXact == OldCommittedSxact));

            oldpredlock = nextpredlock;
        }
        LWLockRelease(SerializableXactHashLock);

        if (removeOld)
        {
            Assert(SHMQueueEmpty(&oldtarget->predicateLocks));
            RemoveTargetIfNoLongerUsed(oldtarget, oldtargettaghash);
        }
    }


exit:
    /* Release partition locks in reverse order of acquisition. */
    if (oldpartitionLock < newpartitionLock)
    {
        LWLockRelease(newpartitionLock);
        LWLockRelease(oldpartitionLock);
    }
    else if (oldpartitionLock > newpartitionLock)
    {
        LWLockRelease(oldpartitionLock);
        LWLockRelease(newpartitionLock);
    }
    else
        LWLockRelease(newpartitionLock);

    if (removeOld)
    {
        /* We shouldn't run out of memory if we're moving locks */
        Assert(!outOfShmem);

        /* Put the scrach entry back */
        RestoreScratchTarget(false);
    }

    return !outOfShmem;
}

static bool XidIsConcurrent ( TransactionId  xid  )  [static]

Variable Documentation

Definition at line 377 of file predicate.c.

HTAB* LocalPredicateLockHash = NULL [static]

Definition at line 392 of file predicate.c.

SERIALIZABLEXACT* MySerializableXact = InvalidSerializableXact [static]

Definition at line 399 of file predicate.c.

bool MyXactDidWrite = false [static]

Definition at line 347 of file predicate.c.

Definition at line 339 of file predicate.c.

Definition at line 305 of file predicate.c.

Definition at line 376 of file predicate.c.

Definition at line 375 of file predicate.c.

Definition at line 362 of file predicate.c.

Definition at line 368 of file predicate.c.

int ScratchPartitionLock [static]

Definition at line 386 of file predicate.c.

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

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

Definition at line 384 of file predicate.c.

Definition at line 385 of file predicate.c.

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

Definition at line 374 of file predicate.c.