Header And Logo

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

Data Structures | Defines | Typedefs | Functions | Variables

lock.c File Reference

#include "postgres.h"
#include <signal.h>
#include <unistd.h>
#include "access/transam.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "storage/proc.h"
#include "storage/sinvaladt.h"
#include "storage/spin.h"
#include "storage/standby.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/resowner_private.h"
Include dependency graph for lock.c:

Go to the source code of this file.

Data Structures

struct  TwoPhaseLockRecord
struct  FastPathStrongRelationLockData

Defines

#define NLOCKENTS()   mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
#define FAST_PATH_BITS_PER_SLOT   3
#define FAST_PATH_LOCKNUMBER_OFFSET   1
#define FAST_PATH_MASK   ((1 << FAST_PATH_BITS_PER_SLOT) - 1)
#define FAST_PATH_GET_BITS(proc, n)   (((proc)->fpLockBits >> (FAST_PATH_BITS_PER_SLOT * n)) & FAST_PATH_MASK)
#define FAST_PATH_BIT_POSITION(n, l)
#define FAST_PATH_SET_LOCKMODE(proc, n, l)   (proc)->fpLockBits |= UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l)
#define FAST_PATH_CLEAR_LOCKMODE(proc, n, l)   (proc)->fpLockBits &= ~(UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l))
#define FAST_PATH_CHECK_LOCKMODE(proc, n, l)   ((proc)->fpLockBits & (UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l)))
#define EligibleForRelationFastPath(locktag, mode)
#define ConflictsWithRelationFastPath(locktag, mode)
#define FAST_PATH_STRONG_LOCK_HASH_BITS   10
#define FAST_PATH_STRONG_LOCK_HASH_PARTITIONS   (1 << FAST_PATH_STRONG_LOCK_HASH_BITS)
#define FastPathStrongLockHashPartition(hashcode)   ((hashcode) % FAST_PATH_STRONG_LOCK_HASH_PARTITIONS)
#define LOCK_PRINT(where, lock, type)
#define PROCLOCK_PRINT(where, proclockP)

Typedefs

typedef struct TwoPhaseLockRecord TwoPhaseLockRecord

Functions

static bool FastPathGrantRelationLock (Oid relid, LOCKMODE lockmode)
static bool FastPathUnGrantRelationLock (Oid relid, LOCKMODE lockmode)
static bool FastPathTransferRelationLocks (LockMethod lockMethodTable, const LOCKTAG *locktag, uint32 hashcode)
static PROCLOCKFastPathGetRelationLockEntry (LOCALLOCK *locallock)
static uint32 proclock_hash (const void *key, Size keysize)
static void RemoveLocalLock (LOCALLOCK *locallock)
static PROCLOCKSetupLockInTable (LockMethod lockMethodTable, PGPROC *proc, const LOCKTAG *locktag, uint32 hashcode, LOCKMODE lockmode)
static void GrantLockLocal (LOCALLOCK *locallock, ResourceOwner owner)
static void BeginStrongLockAcquire (LOCALLOCK *locallock, uint32 fasthashcode)
static void FinishStrongLockAcquire (void)
static void WaitOnLock (LOCALLOCK *locallock, ResourceOwner owner)
static void ReleaseLockIfHeld (LOCALLOCK *locallock, bool sessionLock)
static void LockReassignOwner (LOCALLOCK *locallock, ResourceOwner parent)
static bool UnGrantLock (LOCK *lock, LOCKMODE lockmode, PROCLOCK *proclock, LockMethod lockMethodTable)
static void CleanUpLock (LOCK *lock, PROCLOCK *proclock, LockMethod lockMethodTable, uint32 hashcode, bool wakeupNeeded)
static void LockRefindAndRelease (LockMethod lockMethodTable, PGPROC *proc, LOCKTAG *locktag, LOCKMODE lockmode, bool decrement_strong_lock_count)
void InitLocks (void)
LockMethod GetLocksMethodTable (const LOCK *lock)
uint32 LockTagHashCode (const LOCKTAG *locktag)
static uint32 ProcLockHashCode (const PROCLOCKTAG *proclocktag, uint32 hashcode)
bool DoLockModesConflict (LOCKMODE mode1, LOCKMODE mode2)
bool LockHasWaiters (const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
LockAcquireResult LockAcquire (const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait)
LockAcquireResult LockAcquireExtended (const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait, bool reportMemoryError)
int LockCheckConflicts (LockMethod lockMethodTable, LOCKMODE lockmode, LOCK *lock, PROCLOCK *proclock, PGPROC *proc)
void GrantLock (LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode)
void AbortStrongLockAcquire (void)
void GrantAwaitedLock (void)
void RemoveFromWaitQueue (PGPROC *proc, uint32 hashcode)
bool LockRelease (const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
void LockReleaseAll (LOCKMETHODID lockmethodid, bool allLocks)
void LockReleaseSession (LOCKMETHODID lockmethodid)
void LockReleaseCurrentOwner (LOCALLOCK **locallocks, int nlocks)
void LockReassignCurrentOwner (LOCALLOCK **locallocks, int nlocks)
VirtualTransactionIdGetLockConflicts (const LOCKTAG *locktag, LOCKMODE lockmode)
void AtPrepare_Locks (void)
void PostPrepare_Locks (TransactionId xid)
Size LockShmemSize (void)
LockDataGetLockStatusData (void)
xl_standby_lockGetRunningTransactionLocks (int *nlocks)
const char * GetLockmodeName (LOCKMETHODID lockmethodid, LOCKMODE mode)
void lock_twophase_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
void lock_twophase_standby_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
void lock_twophase_postcommit (TransactionId xid, uint16 info, void *recdata, uint32 len)
void lock_twophase_postabort (TransactionId xid, uint16 info, void *recdata, uint32 len)
void VirtualXactLockTableInsert (VirtualTransactionId vxid)
void VirtualXactLockTableCleanup ()
bool VirtualXactLock (VirtualTransactionId vxid, bool wait)

Variables

int max_locks_per_xact
static const LOCKMASK LockConflicts []
static const char *const lock_mode_names []
static bool Dummy_trace = false
static const LockMethodData default_lockmethod
static const LockMethodData user_lockmethod
static const LockMethod LockMethods []
static int FastPathLocalUseCount = 0
FastPathStrongRelationLockDataFastPathStrongRelationLocks
static HTABLockMethodLockHash
static HTABLockMethodProcLockHash
static HTABLockMethodLocalHash
static LOCALLOCKStrongLockInProgress
static LOCALLOCKawaitedLock
static ResourceOwner awaitedOwner

Define Documentation

#define ConflictsWithRelationFastPath (   locktag,
  mode 
)
Value:
((locktag)->locktag_lockmethodid == DEFAULT_LOCKMETHOD && \
    (locktag)->locktag_type == LOCKTAG_RELATION && \
    (locktag)->locktag_field1 != InvalidOid && \
    (mode) > ShareUpdateExclusiveLock)

Definition at line 202 of file lock.c.

Referenced by GetLockConflicts(), lock_twophase_recover(), LockAcquireExtended(), and LockRefindAndRelease().

#define EligibleForRelationFastPath (   locktag,
  mode 
)
Value:
((locktag)->locktag_lockmethodid == DEFAULT_LOCKMETHOD && \
    (locktag)->locktag_type == LOCKTAG_RELATION && \
    (locktag)->locktag_field1 == MyDatabaseId && \
    MyDatabaseId != InvalidOid && \
    (mode) < ShareUpdateExclusiveLock)

Definition at line 196 of file lock.c.

Referenced by LockAcquireExtended(), LockRelease(), and LockReleaseAll().

#define FAST_PATH_BIT_POSITION (   n,
  l 
)
#define FAST_PATH_BITS_PER_SLOT   3

Definition at line 171 of file lock.c.

#define FAST_PATH_CHECK_LOCKMODE (   proc,
  n,
  l 
)    ((proc)->fpLockBits & (UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l)))
#define FAST_PATH_CLEAR_LOCKMODE (   proc,
  n,
  l 
)    (proc)->fpLockBits &= ~(UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l))
#define FAST_PATH_GET_BITS (   proc,
  n 
)    (((proc)->fpLockBits >> (FAST_PATH_BITS_PER_SLOT * n)) & FAST_PATH_MASK)
#define FAST_PATH_LOCKNUMBER_OFFSET   1

Definition at line 172 of file lock.c.

Referenced by FastPathTransferRelationLocks().

#define FAST_PATH_MASK   ((1 << FAST_PATH_BITS_PER_SLOT) - 1)

Definition at line 173 of file lock.c.

#define FAST_PATH_SET_LOCKMODE (   proc,
  n,
  l 
)    (proc)->fpLockBits |= UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l)

Definition at line 181 of file lock.c.

Referenced by FastPathGrantRelationLock().

#define FAST_PATH_STRONG_LOCK_HASH_BITS   10

Definition at line 229 of file lock.c.

#define FAST_PATH_STRONG_LOCK_HASH_PARTITIONS   (1 << FAST_PATH_STRONG_LOCK_HASH_BITS)

Definition at line 230 of file lock.c.

#define FastPathStrongLockHashPartition (   hashcode  )     ((hashcode) % FAST_PATH_STRONG_LOCK_HASH_PARTITIONS)
#define LOCK_PRINT (   where,
  lock,
  type 
)
#define NLOCKENTS (  )     mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))

Definition at line 53 of file lock.c.

Referenced by InitLocks(), and LockShmemSize().

#define PROCLOCK_PRINT (   where,
  proclockP 
)

Typedef Documentation


Function Documentation

void AbortStrongLockAcquire ( void   ) 
void AtPrepare_Locks ( void   ) 

Definition at line 2926 of file lock.c.

References ereport, errcode(), errmsg(), ERROR, FastPathGetRelationLockEntry(), hash_seq_init(), hash_seq_search(), LOCALLOCK::holdsStrongLockCount, i, LOCALLOCK::lock, LOCALLOCKTAG::lock, TwoPhaseLockRecord::lockmode, LOCALLOCK::lockOwners, TwoPhaseLockRecord::locktag, LOCKTAG::locktag_type, LOCKTAG_VIRTUALTRANSACTION, LOCALLOCKTAG::mode, PROCLOCKTAG::myLock, LOCALLOCK::nLocks, NULL, LOCALLOCK::numLockOwners, LOCALLOCK::proclock, RegisterTwoPhaseRecord(), PROCLOCK::tag, LOCALLOCK::tag, and TWOPHASE_RM_LOCK_ID.

Referenced by PrepareTransaction().

{
    HASH_SEQ_STATUS status;
    LOCALLOCK  *locallock;

    /*
     * For the most part, we don't need to touch shared memory for this ---
     * all the necessary state information is in the locallock table.
     * Fast-path locks are an exception, however: we move any such locks to
     * the main table before allowing PREPARE TRANSACTION to succeed.
     */
    hash_seq_init(&status, LockMethodLocalHash);

    while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
    {
        TwoPhaseLockRecord record;
        LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
        bool        haveSessionLock;
        bool        haveXactLock;
        int         i;

        /*
         * Ignore VXID locks.  We don't want those to be held by prepared
         * transactions, since they aren't meaningful after a restart.
         */
        if (locallock->tag.lock.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
            continue;

        /* Ignore it if we don't actually hold the lock */
        if (locallock->nLocks <= 0)
            continue;

        /* Scan to see whether we hold it at session or transaction level */
        haveSessionLock = haveXactLock = false;
        for (i = locallock->numLockOwners - 1; i >= 0; i--)
        {
            if (lockOwners[i].owner == NULL)
                haveSessionLock = true;
            else
                haveXactLock = true;
        }

        /* Ignore it if we have only session lock */
        if (!haveXactLock)
            continue;

        /*
         * If we have both session- and transaction-level locks, fail.  This
         * should never happen with regular locks, since we only take those at
         * session level in some special operations like VACUUM.  It's
         * possible to hit this with advisory locks, though.
         *
         * It would be nice if we could keep the session hold and give away
         * the transactional hold to the prepared xact.  However, that would
         * require two PROCLOCK objects, and we cannot be sure that another
         * PROCLOCK will be available when it comes time for PostPrepare_Locks
         * to do the deed.  So for now, we error out while we can still do so
         * safely.
         */
        if (haveSessionLock)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("cannot PREPARE while holding both session-level and transaction-level locks on the same object")));

        /*
         * If the local lock was taken via the fast-path, we need to move it
         * to the primary lock table, or just get a pointer to the existing
         * primary lock table entry if by chance it's already been
         * transferred.
         */
        if (locallock->proclock == NULL)
        {
            locallock->proclock = FastPathGetRelationLockEntry(locallock);
            locallock->lock = locallock->proclock->tag.myLock;
        }

        /*
         * Arrange to not release any strong lock count held by this lock
         * entry.  We must retain the count until the prepared transaction is
         * committed or rolled back.
         */
        locallock->holdsStrongLockCount = FALSE;

        /*
         * Create a 2PC record.
         */
        memcpy(&(record.locktag), &(locallock->tag.lock), sizeof(LOCKTAG));
        record.lockmode = locallock->tag.mode;

        RegisterTwoPhaseRecord(TWOPHASE_RM_LOCK_ID, 0,
                               &record, sizeof(TwoPhaseLockRecord));
    }
}

static void BeginStrongLockAcquire ( LOCALLOCK locallock,
uint32  fasthashcode 
) [static]

Definition at line 1488 of file lock.c.

References Assert, FastPathStrongRelationLockData::count, FALSE, LOCALLOCK::holdsStrongLockCount, FastPathStrongRelationLockData::mutex, NULL, SpinLockAcquire, and SpinLockRelease.

Referenced by LockAcquireExtended().

{
    Assert(StrongLockInProgress == NULL);
    Assert(locallock->holdsStrongLockCount == FALSE);

    /*
     * Adding to a memory location is not atomic, so we take a spinlock to
     * ensure we don't collide with someone else trying to bump the count at
     * the same time.
     *
     * XXX: It might be worth considering using an atomic fetch-and-add
     * instruction here, on architectures where that is supported.
     */

    SpinLockAcquire(&FastPathStrongRelationLocks->mutex);
    FastPathStrongRelationLocks->count[fasthashcode]++;
    locallock->holdsStrongLockCount = TRUE;
    StrongLockInProgress = locallock;
    SpinLockRelease(&FastPathStrongRelationLocks->mutex);
}

static void CleanUpLock ( LOCK lock,
PROCLOCK proclock,
LockMethod  lockMethodTable,
uint32  hashcode,
bool  wakeupNeeded 
) [static]

Definition at line 1405 of file lock.c.

References Assert, elog, HASH_REMOVE, hash_search_with_hash_value(), PROCLOCK::holdMask, LOCK_PRINT, PROCLOCK::lockLink, LOCK::nRequested, NULL, PANIC, PROCLOCK::procLink, PROCLOCK_PRINT, ProcLockHashCode(), LOCK::procLocks, ProcLockWakeup(), SHMQueueDelete(), SHMQueueEmpty(), LOCK::tag, and PROCLOCK::tag.

Referenced by LockRefindAndRelease(), LockRelease(), LockReleaseAll(), and RemoveFromWaitQueue().

{
    /*
     * If this was my last hold on this lock, delete my entry in the proclock
     * table.
     */
    if (proclock->holdMask == 0)
    {
        uint32      proclock_hashcode;

        PROCLOCK_PRINT("CleanUpLock: deleting", proclock);
        SHMQueueDelete(&proclock->lockLink);
        SHMQueueDelete(&proclock->procLink);
        proclock_hashcode = ProcLockHashCode(&proclock->tag, hashcode);
        if (!hash_search_with_hash_value(LockMethodProcLockHash,
                                         (void *) &(proclock->tag),
                                         proclock_hashcode,
                                         HASH_REMOVE,
                                         NULL))
            elog(PANIC, "proclock table corrupted");
    }

    if (lock->nRequested == 0)
    {
        /*
         * The caller just released the last lock, so garbage-collect the lock
         * object.
         */
        LOCK_PRINT("CleanUpLock: deleting", lock, 0);
        Assert(SHMQueueEmpty(&(lock->procLocks)));
        if (!hash_search_with_hash_value(LockMethodLockHash,
                                         (void *) &(lock->tag),
                                         hashcode,
                                         HASH_REMOVE,
                                         NULL))
            elog(PANIC, "lock table corrupted");
    }
    else if (wakeupNeeded)
    {
        /* There are waiters on this lock, so wake them up. */
        ProcLockWakeup(lockMethodTable, lock);
    }
}

bool DoLockModesConflict ( LOCKMODE  mode1,
LOCKMODE  mode2 
)

Definition at line 545 of file lock.c.

References LockMethodData::conflictTab, and LOCKBIT_ON.

Referenced by Do_MultiXactIdWait().

{
    LockMethod  lockMethodTable = LockMethods[DEFAULT_LOCKMETHOD];

    if (lockMethodTable->conflictTab[mode1] & LOCKBIT_ON(mode2))
        return true;

    return false;
}

static PROCLOCK * FastPathGetRelationLockEntry ( LOCALLOCK locallock  )  [static]

Definition at line 2522 of file lock.c.

References PGPROC::backendLock, elog, ereport, errcode(), errhint(), errmsg(), ERROR, FAST_PATH_CHECK_LOCKMODE, FAST_PATH_CLEAR_LOCKMODE, FAST_PATH_GET_BITS, PGPROC::fpRelId, GrantLock(), hash_search_with_hash_value(), LOCALLOCK::hashcode, LOCALLOCKTAG::lock, LockHashPartitionLock, LOCKTAG::locktag_field2, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), LOCALLOCKTAG::mode, PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, MyProc, NULL, ProcLockHashCode(), SetupLockInTable(), PROCLOCK::tag, and LOCALLOCK::tag.

Referenced by AtPrepare_Locks().

{
    LockMethod  lockMethodTable = LockMethods[DEFAULT_LOCKMETHOD];
    LOCKTAG    *locktag = &locallock->tag.lock;
    PROCLOCK   *proclock = NULL;
    LWLockId    partitionLock = LockHashPartitionLock(locallock->hashcode);
    Oid         relid = locktag->locktag_field2;
    uint32      f;

    LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);

    for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; f++)
    {
        uint32      lockmode;

        /* Look for an allocated slot matching the given relid. */
        if (relid != MyProc->fpRelId[f] || FAST_PATH_GET_BITS(MyProc, f) == 0)
            continue;

        /* If we don't have a lock of the given mode, forget it! */
        lockmode = locallock->tag.mode;
        if (!FAST_PATH_CHECK_LOCKMODE(MyProc, f, lockmode))
            break;

        /* Find or create lock object. */
        LWLockAcquire(partitionLock, LW_EXCLUSIVE);

        proclock = SetupLockInTable(lockMethodTable, MyProc, locktag,
                                    locallock->hashcode, lockmode);
        if (!proclock)
        {
            LWLockRelease(partitionLock);
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of shared memory"),
                     errhint("You might need to increase max_locks_per_transaction.")));
        }
        GrantLock(proclock->tag.myLock, proclock, lockmode);
        FAST_PATH_CLEAR_LOCKMODE(MyProc, f, lockmode);

        LWLockRelease(partitionLock);
    }

    LWLockRelease(MyProc->backendLock);

    /* Lock may have already been transferred by some other backend. */
    if (proclock == NULL)
    {
        LOCK       *lock;
        PROCLOCKTAG proclocktag;
        uint32      proclock_hashcode;

        LWLockAcquire(partitionLock, LW_SHARED);

        lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
                                                    (void *) locktag,
                                                    locallock->hashcode,
                                                    HASH_FIND,
                                                    NULL);
        if (!lock)
            elog(ERROR, "failed to re-find shared lock object");

        proclocktag.myLock = lock;
        proclocktag.myProc = MyProc;

        proclock_hashcode = ProcLockHashCode(&proclocktag, locallock->hashcode);
        proclock = (PROCLOCK *)
            hash_search_with_hash_value(LockMethodProcLockHash,
                                        (void *) &proclocktag,
                                        proclock_hashcode,
                                        HASH_FIND,
                                        NULL);
        if (!proclock)
            elog(ERROR, "failed to re-find shared proclock object");
        LWLockRelease(partitionLock);
    }

    return proclock;
}

static bool FastPathGrantRelationLock ( Oid  relid,
LOCKMODE  lockmode 
) [static]

Definition at line 2374 of file lock.c.

References Assert, FAST_PATH_CHECK_LOCKMODE, FAST_PATH_GET_BITS, FAST_PATH_SET_LOCKMODE, FastPathLocalUseCount, PGPROC::fpRelId, and MyProc.

Referenced by LockAcquireExtended().

{
    uint32      f;
    uint32      unused_slot = FP_LOCK_SLOTS_PER_BACKEND;

    /* Scan for existing entry for this relid, remembering empty slot. */
    for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; f++)
    {
        if (FAST_PATH_GET_BITS(MyProc, f) == 0)
            unused_slot = f;
        else if (MyProc->fpRelId[f] == relid)
        {
            Assert(!FAST_PATH_CHECK_LOCKMODE(MyProc, f, lockmode));
            FAST_PATH_SET_LOCKMODE(MyProc, f, lockmode);
            return true;
        }
    }

    /* If no existing entry, use any empty slot. */
    if (unused_slot < FP_LOCK_SLOTS_PER_BACKEND)
    {
        MyProc->fpRelId[unused_slot] = relid;
        FAST_PATH_SET_LOCKMODE(MyProc, unused_slot, lockmode);
        ++FastPathLocalUseCount;
        return true;
    }

    /* No existing entry, and no empty slot. */
    return false;
}

static bool FastPathTransferRelationLocks ( LockMethod  lockMethodTable,
const LOCKTAG locktag,
uint32  hashcode 
) [static]

Definition at line 2440 of file lock.c.

References PROC_HDR::allProcCount, PROC_HDR::allProcs, PGPROC::backendLock, PGPROC::databaseId, FAST_PATH_CHECK_LOCKMODE, FAST_PATH_CLEAR_LOCKMODE, FAST_PATH_GET_BITS, FAST_PATH_LOCKNUMBER_OFFSET, PGPROC::fpRelId, GrantLock(), i, LockHashPartitionLock, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PROCLOCKTAG::myLock, ProcGlobal, SetupLockInTable(), and PROCLOCK::tag.

Referenced by LockAcquireExtended().

{
    LWLockId    partitionLock = LockHashPartitionLock(hashcode);
    Oid         relid = locktag->locktag_field2;
    uint32      i;

    /*
     * Every PGPROC that can potentially hold a fast-path lock is present in
     * ProcGlobal->allProcs.  Prepared transactions are not, but any
     * outstanding fast-path locks held by prepared transactions are
     * transferred to the main lock table.
     */
    for (i = 0; i < ProcGlobal->allProcCount; i++)
    {
        PGPROC     *proc = &ProcGlobal->allProcs[i];
        uint32      f;

        LWLockAcquire(proc->backendLock, LW_EXCLUSIVE);

        /*
         * If the target backend isn't referencing the same database as the
         * lock, then we needn't examine the individual relation IDs at all;
         * none of them can be relevant.
         *
         * proc->databaseId is set at backend startup time and never changes
         * thereafter, so it might be safe to perform this test before
         * acquiring proc->backendLock.  In particular, it's certainly safe to
         * assume that if the target backend holds any fast-path locks, it
         * must have performed a memory-fencing operation (in particular, an
         * LWLock acquisition) since setting proc->databaseId.  However, it's
         * less clear that our backend is certain to have performed a memory
         * fencing operation since the other backend set proc->databaseId.  So
         * for now, we test it after acquiring the LWLock just to be safe.
         */
        if (proc->databaseId != locktag->locktag_field1)
        {
            LWLockRelease(proc->backendLock);
            continue;
        }

        for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; f++)
        {
            uint32      lockmode;

            /* Look for an allocated slot matching the given relid. */
            if (relid != proc->fpRelId[f] || FAST_PATH_GET_BITS(proc, f) == 0)
                continue;

            /* Find or create lock object. */
            LWLockAcquire(partitionLock, LW_EXCLUSIVE);
            for (lockmode = FAST_PATH_LOCKNUMBER_OFFSET;
            lockmode < FAST_PATH_LOCKNUMBER_OFFSET + FAST_PATH_BITS_PER_SLOT;
                 ++lockmode)
            {
                PROCLOCK   *proclock;

                if (!FAST_PATH_CHECK_LOCKMODE(proc, f, lockmode))
                    continue;
                proclock = SetupLockInTable(lockMethodTable, proc, locktag,
                                            hashcode, lockmode);
                if (!proclock)
                {
                    LWLockRelease(partitionLock);
                    return false;
                }
                GrantLock(proclock->tag.myLock, proclock, lockmode);
                FAST_PATH_CLEAR_LOCKMODE(proc, f, lockmode);
            }
            LWLockRelease(partitionLock);
        }
        LWLockRelease(proc->backendLock);
    }
    return true;
}

static bool FastPathUnGrantRelationLock ( Oid  relid,
LOCKMODE  lockmode 
) [static]

Definition at line 2411 of file lock.c.

References Assert, FAST_PATH_CHECK_LOCKMODE, FAST_PATH_CLEAR_LOCKMODE, FAST_PATH_GET_BITS, FastPathLocalUseCount, PGPROC::fpRelId, and MyProc.

Referenced by LockRelease(), and LockReleaseAll().

{
    uint32      f;
    bool        result = false;

    FastPathLocalUseCount = 0;
    for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; f++)
    {
        if (MyProc->fpRelId[f] == relid
            && FAST_PATH_CHECK_LOCKMODE(MyProc, f, lockmode))
        {
            Assert(!result);
            FAST_PATH_CLEAR_LOCKMODE(MyProc, f, lockmode);
            result = true;
        }
        if (FAST_PATH_GET_BITS(MyProc, f) != 0)
            ++FastPathLocalUseCount;
    }
    return result;
}

static void FinishStrongLockAcquire ( void   )  [static]

Definition at line 1514 of file lock.c.

Referenced by LockAcquireExtended().

VirtualTransactionId* GetLockConflicts ( const LOCKTAG locktag,
LOCKMODE  lockmode 
)

Definition at line 2619 of file lock.c.

References PROC_HDR::allProcCount, PROC_HDR::allProcs, PGPROC::backendLock, ConflictsWithRelationFastPath, LockMethodData::conflictTab, PGPROC::databaseId, elog, ERROR, FAST_PATH_GET_BITS, PGPROC::fpRelId, GET_VXID_FROM_PGPROC, hash_search_with_hash_value(), PROCLOCK::holdMask, i, InHotStandby, lengthof, LockHashPartitionLock, PROCLOCK::lockLink, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_lockmethodid, LockTagHashCode(), LW_SHARED, LWLockAcquire(), LWLockRelease(), MaxBackends, MemoryContextAlloc(), PROCLOCKTAG::myProc, MyProc, NULL, LockMethodData::numLockModes, offsetof, palloc0(), PANIC, ProcGlobal, LOCK::procLocks, SHMQueueNext(), PROCLOCK::tag, TopMemoryContext, VirtualTransactionIdEquals, and VirtualTransactionIdIsValid.

Referenced by DefineIndex(), index_drop(), and ResolveRecoveryConflictWithLock().

{
    static VirtualTransactionId *vxids;
    LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
    LockMethod  lockMethodTable;
    LOCK       *lock;
    LOCKMASK    conflictMask;
    SHM_QUEUE  *procLocks;
    PROCLOCK   *proclock;
    uint32      hashcode;
    LWLockId    partitionLock;
    int         count = 0;
    int         fast_count = 0;

    if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
        elog(ERROR, "unrecognized lock method: %d", lockmethodid);
    lockMethodTable = LockMethods[lockmethodid];
    if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
        elog(ERROR, "unrecognized lock mode: %d", lockmode);

    /*
     * Allocate memory to store results, and fill with InvalidVXID.  We only
     * need enough space for MaxBackends + a terminator, since prepared xacts
     * don't count. InHotStandby allocate once in TopMemoryContext.
     */
    if (InHotStandby)
    {
        if (vxids == NULL)
            vxids = (VirtualTransactionId *)
                MemoryContextAlloc(TopMemoryContext,
                           sizeof(VirtualTransactionId) * (MaxBackends + 1));
    }
    else
        vxids = (VirtualTransactionId *)
            palloc0(sizeof(VirtualTransactionId) * (MaxBackends + 1));

    /* Compute hash code and partiton lock, and look up conflicting modes. */
    hashcode = LockTagHashCode(locktag);
    partitionLock = LockHashPartitionLock(hashcode);
    conflictMask = lockMethodTable->conflictTab[lockmode];

    /*
     * Fast path locks might not have been entered in the primary lock table.
     * If the lock we're dealing with could conflict with such a lock, we must
     * examine each backend's fast-path array for conflicts.
     */
    if (ConflictsWithRelationFastPath(locktag, lockmode))
    {
        int         i;
        Oid         relid = locktag->locktag_field2;
        VirtualTransactionId vxid;

        /*
         * Iterate over relevant PGPROCs.  Anything held by a prepared
         * transaction will have been transferred to the primary lock table,
         * so we need not worry about those.  This is all a bit fuzzy, because
         * new locks could be taken after we've visited a particular
         * partition, but the callers had better be prepared to deal with that
         * anyway, since the locks could equally well be taken between the
         * time we return the value and the time the caller does something
         * with it.
         */
        for (i = 0; i < ProcGlobal->allProcCount; i++)
        {
            PGPROC     *proc = &ProcGlobal->allProcs[i];
            uint32      f;

            /* A backend never blocks itself */
            if (proc == MyProc)
                continue;

            LWLockAcquire(proc->backendLock, LW_SHARED);

            /*
             * If the target backend isn't referencing the same database as the
             * lock, then we needn't examine the individual relation IDs at
             * all; none of them can be relevant.
             *
             * See FastPathTransferLocks() for discussion of why we do this
             * test after acquiring the lock.
             */
            if (proc->databaseId != locktag->locktag_field1)
            {
                LWLockRelease(proc->backendLock);
                continue;
            }

            for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; f++)
            {
                uint32      lockmask;

                /* Look for an allocated slot matching the given relid. */
                if (relid != proc->fpRelId[f])
                    continue;
                lockmask = FAST_PATH_GET_BITS(proc, f);
                if (!lockmask)
                    continue;
                lockmask <<= FAST_PATH_LOCKNUMBER_OFFSET;

                /*
                 * There can only be one entry per relation, so if we found it
                 * and it doesn't conflict, we can skip the rest of the slots.
                 */
                if ((lockmask & conflictMask) == 0)
                    break;

                /* Conflict! */
                GET_VXID_FROM_PGPROC(vxid, *proc);

                /*
                 * If we see an invalid VXID, then either the xact has already
                 * committed (or aborted), or it's a prepared xact.  In either
                 * case we may ignore it.
                 */
                if (VirtualTransactionIdIsValid(vxid))
                    vxids[count++] = vxid;
                break;
            }

            LWLockRelease(proc->backendLock);
        }
    }

    /* Remember how many fast-path conflicts we found. */
    fast_count = count;

    /*
     * Look up the lock object matching the tag.
     */
    LWLockAcquire(partitionLock, LW_SHARED);

    lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
                                                (const void *) locktag,
                                                hashcode,
                                                HASH_FIND,
                                                NULL);
    if (!lock)
    {
        /*
         * If the lock object doesn't exist, there is nothing holding a lock
         * on this lockable object.
         */
        LWLockRelease(partitionLock);
        return vxids;
    }

    /*
     * Examine each existing holder (or awaiter) of the lock.
     */

    procLocks = &(lock->procLocks);

    proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
                                         offsetof(PROCLOCK, lockLink));

    while (proclock)
    {
        if (conflictMask & proclock->holdMask)
        {
            PGPROC     *proc = proclock->tag.myProc;

            /* A backend never blocks itself */
            if (proc != MyProc)
            {
                VirtualTransactionId vxid;

                GET_VXID_FROM_PGPROC(vxid, *proc);

                /*
                 * If we see an invalid VXID, then either the xact has already
                 * committed (or aborted), or it's a prepared xact.  In either
                 * case we may ignore it.
                 */
                if (VirtualTransactionIdIsValid(vxid))
                {
                    int         i;

                    /* Avoid duplicate entries. */
                    for (i = 0; i < fast_count; ++i)
                        if (VirtualTransactionIdEquals(vxids[i], vxid))
                            break;
                    if (i >= fast_count)
                        vxids[count++] = vxid;
                }
            }
        }

        proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
                                             offsetof(PROCLOCK, lockLink));
    }

    LWLockRelease(partitionLock);

    if (count > MaxBackends)    /* should never happen */
        elog(PANIC, "too many conflicting locks found");

    return vxids;
}

const char* GetLockmodeName ( LOCKMETHODID  lockmethodid,
LOCKMODE  mode 
)

Definition at line 3486 of file lock.c.

References Assert, lengthof, and LockMethodData::lockModeNames.

Referenced by DeadLockReport(), pg_lock_status(), and ProcSleep().

{
    Assert(lockmethodid > 0 && lockmethodid < lengthof(LockMethods));
    Assert(mode > 0 && mode <= LockMethods[lockmethodid]->numLockModes);
    return LockMethods[lockmethodid]->lockModeNames[mode];
}

LockMethod GetLocksMethodTable ( const LOCK lock  ) 

Definition at line 461 of file lock.c.

References Assert, lengthof, and LOCK_LOCKMETHOD.

Referenced by DeadLockCheck(), and FindLockCycleRecurse().

{
    LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*lock);

    Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
    return LockMethods[lockmethodid];
}

LockData* GetLockStatusData ( void   ) 

Definition at line 3246 of file lock.c.

References PROC_HDR::allProcCount, PROC_HDR::allProcs, Assert, LockInstanceData::backend, VirtualTransactionId::backendId, PGPROC::backendId, PGPROC::backendLock, PGPROC::databaseId, ExclusiveLock, FAST_PATH_GET_BITS, LockInstanceData::fastpath, FirstLockMgrLock, PGPROC::fpLocalTransactionId, PGPROC::fpRelId, PGPROC::fpVXIDLock, hash_get_num_entries(), hash_seq_init(), hash_seq_search(), PROCLOCK::holdMask, LockInstanceData::holdMask, i, VirtualTransactionId::localTransactionId, LOCKBIT_ON, LockData::locks, LockInstanceData::locktag, LW_SHARED, LWLockAcquire(), LWLockRelease(), PGPROC::lxid, LockInstanceData::lxid, MaxBackends, PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, LockData::nelements, palloc(), PGPROC::pid, LockInstanceData::pid, ProcGlobal, repalloc(), SET_LOCKTAG_RELATION, SET_LOCKTAG_VIRTUALTRANSACTION, LOCK::tag, PROCLOCK::tag, PGPROC::waitLock, PGPROC::waitLockMode, and LockInstanceData::waitLockMode.

Referenced by pg_lock_status().

{
    LockData   *data;
    PROCLOCK   *proclock;
    HASH_SEQ_STATUS seqstat;
    int         els;
    int         el;
    int         i;

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

    /* Guess how much space we'll need. */
    els = MaxBackends;
    el = 0;
    data->locks = (LockInstanceData *) palloc(sizeof(LockInstanceData) * els);

    /*
     * First, we iterate through the per-backend fast-path arrays, locking
     * them one at a time.  This might produce an inconsistent picture of the
     * system state, but taking all of those LWLocks at the same time seems
     * impractical (in particular, note MAX_SIMUL_LWLOCKS).  It shouldn't
     * matter too much, because none of these locks can be involved in lock
     * conflicts anyway - anything that might must be present in the main lock
     * table.
     */
    for (i = 0; i < ProcGlobal->allProcCount; ++i)
    {
        PGPROC     *proc = &ProcGlobal->allProcs[i];
        uint32      f;

        LWLockAcquire(proc->backendLock, LW_SHARED);

        for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; ++f)
        {
            LockInstanceData *instance;
            uint32      lockbits = FAST_PATH_GET_BITS(proc, f);

            /* Skip unallocated slots. */
            if (!lockbits)
                continue;

            if (el >= els)
            {
                els += MaxBackends;
                data->locks = (LockInstanceData *)
                    repalloc(data->locks, sizeof(LockInstanceData) * els);
            }

            instance = &data->locks[el];
            SET_LOCKTAG_RELATION(instance->locktag, proc->databaseId,
                                 proc->fpRelId[f]);
            instance->holdMask = lockbits << FAST_PATH_LOCKNUMBER_OFFSET;
            instance->waitLockMode = NoLock;
            instance->backend = proc->backendId;
            instance->lxid = proc->lxid;
            instance->pid = proc->pid;
            instance->fastpath = true;

            el++;
        }

        if (proc->fpVXIDLock)
        {
            VirtualTransactionId vxid;
            LockInstanceData *instance;

            if (el >= els)
            {
                els += MaxBackends;
                data->locks = (LockInstanceData *)
                    repalloc(data->locks, sizeof(LockInstanceData) * els);
            }

            vxid.backendId = proc->backendId;
            vxid.localTransactionId = proc->fpLocalTransactionId;

            instance = &data->locks[el];
            SET_LOCKTAG_VIRTUALTRANSACTION(instance->locktag, vxid);
            instance->holdMask = LOCKBIT_ON(ExclusiveLock);
            instance->waitLockMode = NoLock;
            instance->backend = proc->backendId;
            instance->lxid = proc->lxid;
            instance->pid = proc->pid;
            instance->fastpath = true;

            el++;
        }

        LWLockRelease(proc->backendLock);
    }

    /*
     * Next, acquire lock on the entire shared lock data structure.  We do
     * this so that, at least for locks in the primary lock table, the state
     * will be self-consistent.
     *
     * Since this is a read-only operation, we take shared instead of
     * exclusive lock.  There's not a whole lot of point to this, because all
     * the normal operations require exclusive lock, but it doesn't hurt
     * anything either. It will at least allow two backends to do
     * GetLockStatusData in parallel.
     *
     * Must grab LWLocks in partition-number order to avoid LWLock deadlock.
     */
    for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
        LWLockAcquire(FirstLockMgrLock + i, LW_SHARED);

    /* Now we can safely count the number of proclocks */
    data->nelements = el + hash_get_num_entries(LockMethodProcLockHash);
    if (data->nelements > els)
    {
        els = data->nelements;
        data->locks = (LockInstanceData *)
            repalloc(data->locks, sizeof(LockInstanceData) * els);
    }

    /* Now scan the tables to copy the data */
    hash_seq_init(&seqstat, LockMethodProcLockHash);

    while ((proclock = (PROCLOCK *) hash_seq_search(&seqstat)))
    {
        PGPROC     *proc = proclock->tag.myProc;
        LOCK       *lock = proclock->tag.myLock;
        LockInstanceData *instance = &data->locks[el];

        memcpy(&instance->locktag, &lock->tag, sizeof(LOCKTAG));
        instance->holdMask = proclock->holdMask;
        if (proc->waitLock == proclock->tag.myLock)
            instance->waitLockMode = proc->waitLockMode;
        else
            instance->waitLockMode = NoLock;
        instance->backend = proc->backendId;
        instance->lxid = proc->lxid;
        instance->pid = proc->pid;
        instance->fastpath = false;

        el++;
    }

    /*
     * And release locks.  We do this in reverse order for two reasons: (1)
     * Anyone else who needs more than one of the locks will be trying to lock
     * them in increasing order; we don't want to release the other process
     * until it can get all the locks it needs. (2) This avoids O(N^2)
     * behavior inside LWLockRelease.
     */
    for (i = NUM_LOCK_PARTITIONS; --i >= 0;)
        LWLockRelease(FirstLockMgrLock + i);

    Assert(el == data->nelements);

    return data;
}

xl_standby_lock* GetRunningTransactionLocks ( int *  nlocks  ) 

Definition at line 3405 of file lock.c.

References AccessExclusiveLock, PROC_HDR::allPgXact, xl_standby_lock::dbOid, FirstLockMgrLock, hash_get_num_entries(), hash_seq_init(), hash_seq_search(), PROCLOCK::holdMask, i, LOCKBIT_ON, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG_RELATION, LOCKTAG::locktag_type, LW_SHARED, LWLockAcquire(), LWLockRelease(), PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, palloc(), PGPROC::pgprocno, ProcGlobal, xl_standby_lock::relOid, LOCK::tag, PROCLOCK::tag, TransactionIdIsValid, xl_standby_lock::xid, and PGXACT::xid.

Referenced by LogStandbySnapshot().

{
    PROCLOCK   *proclock;
    HASH_SEQ_STATUS seqstat;
    int         i;
    int         index;
    int         els;
    xl_standby_lock *accessExclusiveLocks;

    /*
     * Acquire lock on the entire shared lock data structure.
     *
     * Must grab LWLocks in partition-number order to avoid LWLock deadlock.
     */
    for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
        LWLockAcquire(FirstLockMgrLock + i, LW_SHARED);

    /* Now we can safely count the number of proclocks */
    els = hash_get_num_entries(LockMethodProcLockHash);

    /*
     * Allocating enough space for all locks in the lock table is overkill,
     * but it's more convenient and faster than having to enlarge the array.
     */
    accessExclusiveLocks = palloc(els * sizeof(xl_standby_lock));

    /* Now scan the tables to copy the data */
    hash_seq_init(&seqstat, LockMethodProcLockHash);

    /*
     * If lock is a currently granted AccessExclusiveLock then it will have
     * just one proclock holder, so locks are never accessed twice in this
     * particular case. Don't copy this code for use elsewhere because in the
     * general case this will give you duplicate locks when looking at
     * non-exclusive lock types.
     */
    index = 0;
    while ((proclock = (PROCLOCK *) hash_seq_search(&seqstat)))
    {
        /* make sure this definition matches the one used in LockAcquire */
        if ((proclock->holdMask & LOCKBIT_ON(AccessExclusiveLock)) &&
            proclock->tag.myLock->tag.locktag_type == LOCKTAG_RELATION)
        {
            PGPROC     *proc = proclock->tag.myProc;
            PGXACT     *pgxact = &ProcGlobal->allPgXact[proc->pgprocno];
            LOCK       *lock = proclock->tag.myLock;
            TransactionId xid = pgxact->xid;

            /*
             * Don't record locks for transactions if we know they have
             * already issued their WAL record for commit but not yet released
             * lock. It is still possible that we see locks held by already
             * complete transactions, if they haven't yet zeroed their xids.
             */
            if (!TransactionIdIsValid(xid))
                continue;

            accessExclusiveLocks[index].xid = xid;
            accessExclusiveLocks[index].dbOid = lock->tag.locktag_field1;
            accessExclusiveLocks[index].relOid = lock->tag.locktag_field2;

            index++;
        }
    }

    /*
     * And release locks.  We do this in reverse order for two reasons: (1)
     * Anyone else who needs more than one of the locks will be trying to lock
     * them in increasing order; we don't want to release the other process
     * until it can get all the locks it needs. (2) This avoids O(N^2)
     * behavior inside LWLockRelease.
     */
    for (i = NUM_LOCK_PARTITIONS; --i >= 0;)
        LWLockRelease(FirstLockMgrLock + i);

    *nlocks = index;
    return accessExclusiveLocks;
}

void GrantAwaitedLock ( void   ) 

Definition at line 1552 of file lock.c.

References GrantLockLocal().

Referenced by LockErrorCleanup(), and ProcSleep().

void GrantLock ( LOCK lock,
PROCLOCK proclock,
LOCKMODE  lockmode 
)

Definition at line 1325 of file lock.c.

References Assert, LOCK::granted, LOCK::grantMask, PROCLOCK::holdMask, LOCK_PRINT, LOCKBIT_OFF, LOCKBIT_ON, LOCK::nGranted, LOCK::nRequested, LOCK::requested, and LOCK::waitMask.

Referenced by FastPathGetRelationLockEntry(), FastPathTransferRelationLocks(), lock_twophase_recover(), LockAcquireExtended(), ProcLockWakeup(), ProcSleep(), and VirtualXactLock().

{
    lock->nGranted++;
    lock->granted[lockmode]++;
    lock->grantMask |= LOCKBIT_ON(lockmode);
    if (lock->granted[lockmode] == lock->requested[lockmode])
        lock->waitMask &= LOCKBIT_OFF(lockmode);
    proclock->holdMask |= LOCKBIT_ON(lockmode);
    LOCK_PRINT("GrantLock", lock, lockmode);
    Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
    Assert(lock->nGranted <= lock->nRequested);
}

static void GrantLockLocal ( LOCALLOCK locallock,
ResourceOwner  owner 
) [static]

Definition at line 1459 of file lock.c.

References Assert, i, LOCALLOCK::lockOwners, LOCALLOCK::maxLockOwners, LOCALLOCKOWNER::nLocks, LOCALLOCK::nLocks, NULL, LOCALLOCK::numLockOwners, LOCALLOCKOWNER::owner, and ResourceOwnerRememberLock().

Referenced by GrantAwaitedLock(), and LockAcquireExtended().

{
    LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
    int         i;

    Assert(locallock->numLockOwners < locallock->maxLockOwners);
    /* Count the total */
    locallock->nLocks++;
    /* Count the per-owner lock */
    for (i = 0; i < locallock->numLockOwners; i++)
    {
        if (lockOwners[i].owner == owner)
        {
            lockOwners[i].nLocks++;
            return;
        }
    }
    lockOwners[i].owner = owner;
    lockOwners[i].nLocks = 1;
    locallock->numLockOwners++;
    if (owner != NULL)
        ResourceOwnerRememberLock(owner, locallock);
}

void InitLocks ( void   ) 

Definition at line 372 of file lock.c.

References HASHCTL::entrysize, HASHCTL::hash, hash_create(), hash_destroy(), HASH_ELEM, HASH_FUNCTION, HASHCTL::keysize, MemSet, FastPathStrongRelationLockData::mutex, NLOCKENTS, HASHCTL::num_partitions, ShmemInitHash(), ShmemInitStruct(), and SpinLockInit.

Referenced by CreateSharedMemoryAndSemaphores().

{
    HASHCTL     info;
    int         hash_flags;
    long        init_table_size,
                max_table_size;
    bool        found;

    /*
     * Compute init/max size to request for lock hashtables.  Note these
     * calculations must agree with LockShmemSize!
     */
    max_table_size = NLOCKENTS();
    init_table_size = max_table_size / 2;

    /*
     * Allocate hash table for LOCK structs.  This stores per-locked-object
     * information.
     */
    MemSet(&info, 0, sizeof(info));
    info.keysize = sizeof(LOCKTAG);
    info.entrysize = sizeof(LOCK);
    info.hash = tag_hash;
    info.num_partitions = NUM_LOCK_PARTITIONS;
    hash_flags = (HASH_ELEM | HASH_FUNCTION | HASH_PARTITION);

    LockMethodLockHash = ShmemInitHash("LOCK hash",
                                       init_table_size,
                                       max_table_size,
                                       &info,
                                       hash_flags);

    /* Assume an average of 2 holders per lock */
    max_table_size *= 2;
    init_table_size *= 2;

    /*
     * Allocate hash table for PROCLOCK structs.  This stores
     * per-lock-per-holder information.
     */
    info.keysize = sizeof(PROCLOCKTAG);
    info.entrysize = sizeof(PROCLOCK);
    info.hash = proclock_hash;
    info.num_partitions = NUM_LOCK_PARTITIONS;
    hash_flags = (HASH_ELEM | HASH_FUNCTION | HASH_PARTITION);

    LockMethodProcLockHash = ShmemInitHash("PROCLOCK hash",
                                           init_table_size,
                                           max_table_size,
                                           &info,
                                           hash_flags);

    /*
     * Allocate fast-path structures.
     */
    FastPathStrongRelationLocks =
        ShmemInitStruct("Fast Path Strong Relation Lock Data",
                        sizeof(FastPathStrongRelationLockData), &found);
    if (!found)
        SpinLockInit(&FastPathStrongRelationLocks->mutex);

    /*
     * Allocate non-shared hash table for LOCALLOCK structs.  This stores lock
     * counts and resource owner information.
     *
     * The non-shared table could already exist in this process (this occurs
     * when the postmaster is recreating shared memory after a backend crash).
     * If so, delete and recreate it.  (We could simply leave it, since it
     * ought to be empty in the postmaster, but for safety let's zap it.)
     */
    if (LockMethodLocalHash)
        hash_destroy(LockMethodLocalHash);

    info.keysize = sizeof(LOCALLOCKTAG);
    info.entrysize = sizeof(LOCALLOCK);
    info.hash = tag_hash;
    hash_flags = (HASH_ELEM | HASH_FUNCTION);

    LockMethodLocalHash = hash_create("LOCALLOCK hash",
                                      16,
                                      &info,
                                      hash_flags);
}

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

Definition at line 3836 of file lock.c.

References lock_twophase_postcommit().

{
    lock_twophase_postcommit(xid, info, recdata, len);
}

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

Definition at line 3810 of file lock.c.

References Assert, elog, ERROR, lengthof, TwoPhaseLockRecord::lockmode, LockRefindAndRelease(), TwoPhaseLockRecord::locktag, LOCKTAG::locktag_lockmethodid, and TwoPhaseGetDummyProc().

Referenced by lock_twophase_postabort().

{
    TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata;
    PGPROC     *proc = TwoPhaseGetDummyProc(xid);
    LOCKTAG    *locktag;
    LOCKMETHODID lockmethodid;
    LockMethod  lockMethodTable;

    Assert(len == sizeof(TwoPhaseLockRecord));
    locktag = &rec->locktag;
    lockmethodid = locktag->locktag_lockmethodid;

    if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
        elog(ERROR, "unrecognized lock method: %d", lockmethodid);
    lockMethodTable = LockMethods[lockmethodid];

    LockRefindAndRelease(lockMethodTable, proc, locktag, rec->lockmode, true);
}

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

Definition at line 3599 of file lock.c.

References Assert, ConflictsWithRelationFastPath, FastPathStrongRelationLockData::count, elog, ereport, errcode(), errhint(), errmsg(), ERROR, FastPathStrongLockHashPartition, LOCK::granted, GrantLock(), LOCK::grantMask, HASH_REMOVE, hash_search_with_hash_value(), PROCLOCK::holdMask, lengthof, LOCK_PRINT, LOCKBIT_ON, LockHashPartition, LockHashPartitionLock, PROCLOCK::lockLink, TwoPhaseLockRecord::lockmode, LockMethodData::lockModeNames, TwoPhaseLockRecord::locktag, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_field3, LOCKTAG::locktag_lockmethodid, LockTagHashCode(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MAX_LOCKMODES, MemSet, FastPathStrongRelationLockData::mutex, PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, PGPROC::myProcLocks, LOCK::nGranted, LOCK::nRequested, NULL, PANIC, PROCLOCK::procLink, PROCLOCK_PRINT, ProcLockHashCode(), LOCK::procLocks, ProcQueueInit(), PROCLOCK::releaseMask, LOCK::requested, SHMQueueEmpty(), SHMQueueInit(), SHMQueueInsertBefore(), SpinLockAcquire, SpinLockRelease, LOCK::tag, TwoPhaseGetDummyProc(), LOCK::waitMask, and LOCK::waitProcs.

{
    TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata;
    PGPROC     *proc = TwoPhaseGetDummyProc(xid);
    LOCKTAG    *locktag;
    LOCKMODE    lockmode;
    LOCKMETHODID lockmethodid;
    LOCK       *lock;
    PROCLOCK   *proclock;
    PROCLOCKTAG proclocktag;
    bool        found;
    uint32      hashcode;
    uint32      proclock_hashcode;
    int         partition;
    LWLockId    partitionLock;
    LockMethod  lockMethodTable;

    Assert(len == sizeof(TwoPhaseLockRecord));
    locktag = &rec->locktag;
    lockmode = rec->lockmode;
    lockmethodid = locktag->locktag_lockmethodid;

    if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
        elog(ERROR, "unrecognized lock method: %d", lockmethodid);
    lockMethodTable = LockMethods[lockmethodid];

    hashcode = LockTagHashCode(locktag);
    partition = LockHashPartition(hashcode);
    partitionLock = LockHashPartitionLock(hashcode);

    LWLockAcquire(partitionLock, LW_EXCLUSIVE);

    /*
     * Find or create a lock with this tag.
     */
    lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
                                                (void *) locktag,
                                                hashcode,
                                                HASH_ENTER_NULL,
                                                &found);
    if (!lock)
    {
        LWLockRelease(partitionLock);
        ereport(ERROR,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of shared memory"),
          errhint("You might need to increase max_locks_per_transaction.")));
    }

    /*
     * if it's a new lock object, initialize it
     */
    if (!found)
    {
        lock->grantMask = 0;
        lock->waitMask = 0;
        SHMQueueInit(&(lock->procLocks));
        ProcQueueInit(&(lock->waitProcs));
        lock->nRequested = 0;
        lock->nGranted = 0;
        MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);
        MemSet(lock->granted, 0, sizeof(int) * MAX_LOCKMODES);
        LOCK_PRINT("lock_twophase_recover: new", lock, lockmode);
    }
    else
    {
        LOCK_PRINT("lock_twophase_recover: found", lock, lockmode);
        Assert((lock->nRequested >= 0) && (lock->requested[lockmode] >= 0));
        Assert((lock->nGranted >= 0) && (lock->granted[lockmode] >= 0));
        Assert(lock->nGranted <= lock->nRequested);
    }

    /*
     * Create the hash key for the proclock table.
     */
    proclocktag.myLock = lock;
    proclocktag.myProc = proc;

    proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);

    /*
     * Find or create a proclock entry with this tag
     */
    proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,
                                                        (void *) &proclocktag,
                                                        proclock_hashcode,
                                                        HASH_ENTER_NULL,
                                                        &found);
    if (!proclock)
    {
        /* Ooops, not enough shmem for the proclock */
        if (lock->nRequested == 0)
        {
            /*
             * There are no other requestors of this lock, so garbage-collect
             * the lock object.  We *must* do this to avoid a permanent leak
             * of shared memory, because there won't be anything to cause
             * anyone to release the lock object later.
             */
            Assert(SHMQueueEmpty(&(lock->procLocks)));
            if (!hash_search_with_hash_value(LockMethodLockHash,
                                             (void *) &(lock->tag),
                                             hashcode,
                                             HASH_REMOVE,
                                             NULL))
                elog(PANIC, "lock table corrupted");
        }
        LWLockRelease(partitionLock);
        ereport(ERROR,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of shared memory"),
          errhint("You might need to increase max_locks_per_transaction.")));
    }

    /*
     * If new, initialize the new entry
     */
    if (!found)
    {
        proclock->holdMask = 0;
        proclock->releaseMask = 0;
        /* Add proclock to appropriate lists */
        SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);
        SHMQueueInsertBefore(&(proc->myProcLocks[partition]),
                             &proclock->procLink);
        PROCLOCK_PRINT("lock_twophase_recover: new", proclock);
    }
    else
    {
        PROCLOCK_PRINT("lock_twophase_recover: found", proclock);
        Assert((proclock->holdMask & ~lock->grantMask) == 0);
    }

    /*
     * lock->nRequested and lock->requested[] count the total number of
     * requests, whether granted or waiting, so increment those immediately.
     */
    lock->nRequested++;
    lock->requested[lockmode]++;
    Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));

    /*
     * We shouldn't already hold the desired lock.
     */
    if (proclock->holdMask & LOCKBIT_ON(lockmode))
        elog(ERROR, "lock %s on object %u/%u/%u is already held",
             lockMethodTable->lockModeNames[lockmode],
             lock->tag.locktag_field1, lock->tag.locktag_field2,
             lock->tag.locktag_field3);

    /*
     * We ignore any possible conflicts and just grant ourselves the lock. Not
     * only because we don't bother, but also to avoid deadlocks when
     * switching from standby to normal mode. See function comment.
     */
    GrantLock(lock, proclock, lockmode);

    /*
     * Bump strong lock count, to make sure any fast-path lock requests won't
     * be granted without consulting the primary lock table.
     */
    if (ConflictsWithRelationFastPath(&lock->tag, lockmode))
    {
        uint32      fasthashcode = FastPathStrongLockHashPartition(hashcode);

        SpinLockAcquire(&FastPathStrongRelationLocks->mutex);
        FastPathStrongRelationLocks->count[fasthashcode]++;
        SpinLockRelease(&FastPathStrongRelationLocks->mutex);
    }

    LWLockRelease(partitionLock);
}

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

Definition at line 3778 of file lock.c.

References AccessExclusiveLock, Assert, elog, ERROR, lengthof, TwoPhaseLockRecord::lockmode, TwoPhaseLockRecord::locktag, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_lockmethodid, LOCKTAG_RELATION, LOCKTAG::locktag_type, and StandbyAcquireAccessExclusiveLock().

{
    TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata;
    LOCKTAG    *locktag;
    LOCKMODE    lockmode;
    LOCKMETHODID lockmethodid;

    Assert(len == sizeof(TwoPhaseLockRecord));
    locktag = &rec->locktag;
    lockmode = rec->lockmode;
    lockmethodid = locktag->locktag_lockmethodid;

    if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
        elog(ERROR, "unrecognized lock method: %d", lockmethodid);

    if (lockmode == AccessExclusiveLock &&
        locktag->locktag_type == LOCKTAG_RELATION)
    {
        StandbyAcquireAccessExclusiveLock(xid,
                                        locktag->locktag_field1 /* dboid */ ,
                                      locktag->locktag_field2 /* reloid */ );
    }
}

LockAcquireResult LockAcquire ( const LOCKTAG locktag,
LOCKMODE  lockmode,
bool  sessionLock,
bool  dontWait 
)
LockAcquireResult LockAcquireExtended ( const LOCKTAG locktag,
LOCKMODE  lockmode,
bool  sessionLock,
bool  dontWait,
bool  reportMemoryError 
)

Definition at line 690 of file lock.c.

References AbortStrongLockAcquire(), AccessExclusiveLock, Assert, PGPROC::backendLock, BeginStrongLockAcquire(), ConflictsWithRelationFastPath, LockMethodData::conflictTab, FastPathStrongRelationLockData::count, CurrentResourceOwner, EligibleForRelationFastPath, elog, ereport, errcode(), errhint(), errmsg(), ERROR, FastPathGrantRelationLock(), FastPathLocalUseCount, FastPathStrongLockHashPartition, FastPathTransferRelationLocks(), FinishStrongLockAcquire(), FP_LOCK_SLOTS_PER_BACKEND, GrantLock(), GrantLockLocal(), HASH_REMOVE, hash_search(), hash_search_with_hash_value(), LOCALLOCK::hashcode, PGPROC::heldLocks, PROCLOCK::holdMask, LOCALLOCK::holdsStrongLockCount, InRecovery, lengthof, LOCALLOCK::lock, LOCALLOCKTAG::lock, LOCK_PRINT, LOCKBIT_ON, LockCheckConflicts(), LockHashPartitionLock, PROCLOCK::lockLink, LockMethodData::lockModeNames, LOCALLOCK::lockOwners, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_field3, LOCKTAG::locktag_field4, LOCKTAG::locktag_lockmethodid, LOCKTAG_OBJECT, LOCKTAG_RELATION, LOCKTAG::locktag_type, LockTagHashCode(), LOG, LogAccessExclusiveLock(), LogAccessExclusiveLockPrepare(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), LOCALLOCK::maxLockOwners, MemoryContextAlloc(), MemSet, LOCALLOCKTAG::mode, PROCLOCKTAG::myLock, MyProc, LOCK::nGranted, LOCALLOCK::nLocks, LOCK::nRequested, NULL, LockMethodData::numLockModes, LOCALLOCK::numLockOwners, PANIC, PROCLOCK::procLink, LOCALLOCK::proclock, PROCLOCK_PRINT, ProcLockHashCode(), RecoveryInProgress(), RemoveLocalLock(), repalloc(), LOCK::requested, RowExclusiveLock, SetupLockInTable(), SHMQueueDelete(), STATUS_FOUND, STATUS_OK, PROCLOCK::tag, TopMemoryContext, LOCK::waitMask, WaitOnLock(), and XLogStandbyInfoActive.

Referenced by LockAcquire(), ResolveRecoveryConflictWithLock(), and StandbyAcquireAccessExclusiveLock().

{
    LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
    LockMethod  lockMethodTable;
    LOCALLOCKTAG localtag;
    LOCALLOCK  *locallock;
    LOCK       *lock;
    PROCLOCK   *proclock;
    bool        found;
    ResourceOwner owner;
    uint32      hashcode;
    LWLockId    partitionLock;
    int         status;
    bool        log_lock = false;

    if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
        elog(ERROR, "unrecognized lock method: %d", lockmethodid);
    lockMethodTable = LockMethods[lockmethodid];
    if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
        elog(ERROR, "unrecognized lock mode: %d", lockmode);

    if (RecoveryInProgress() && !InRecovery &&
        (locktag->locktag_type == LOCKTAG_OBJECT ||
         locktag->locktag_type == LOCKTAG_RELATION) &&
        lockmode > RowExclusiveLock)
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("cannot acquire lock mode %s on database objects while recovery is in progress",
                        lockMethodTable->lockModeNames[lockmode]),
                 errhint("Only RowExclusiveLock or less can be acquired on database objects during recovery.")));

#ifdef LOCK_DEBUG
    if (LOCK_DEBUG_ENABLED(locktag))
        elog(LOG, "LockAcquire: lock [%u,%u] %s",
             locktag->locktag_field1, locktag->locktag_field2,
             lockMethodTable->lockModeNames[lockmode]);
#endif

    /* Identify owner for lock */
    if (sessionLock)
        owner = NULL;
    else
        owner = CurrentResourceOwner;

    /*
     * Find or create a LOCALLOCK entry for this lock and lockmode
     */
    MemSet(&localtag, 0, sizeof(localtag));     /* must clear padding */
    localtag.lock = *locktag;
    localtag.mode = lockmode;

    locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
                                          (void *) &localtag,
                                          HASH_ENTER, &found);

    /*
     * if it's a new locallock object, initialize it
     */
    if (!found)
    {
        locallock->lock = NULL;
        locallock->proclock = NULL;
        locallock->hashcode = LockTagHashCode(&(localtag.lock));
        locallock->nLocks = 0;
        locallock->numLockOwners = 0;
        locallock->maxLockOwners = 8;
        locallock->holdsStrongLockCount = FALSE;
        locallock->lockOwners = NULL;
        locallock->lockOwners = (LOCALLOCKOWNER *)
            MemoryContextAlloc(TopMemoryContext,
                          locallock->maxLockOwners * sizeof(LOCALLOCKOWNER));
    }
    else
    {
        /* Make sure there will be room to remember the lock */
        if (locallock->numLockOwners >= locallock->maxLockOwners)
        {
            int         newsize = locallock->maxLockOwners * 2;

            locallock->lockOwners = (LOCALLOCKOWNER *)
                repalloc(locallock->lockOwners,
                         newsize * sizeof(LOCALLOCKOWNER));
            locallock->maxLockOwners = newsize;
        }
    }
    hashcode = locallock->hashcode;

    /*
     * If we already hold the lock, we can just increase the count locally.
     */
    if (locallock->nLocks > 0)
    {
        GrantLockLocal(locallock, owner);
        return LOCKACQUIRE_ALREADY_HELD;
    }

    /*
     * Emit a WAL record if acquisition of this lock needs to be replayed in a
     * standby server. Only AccessExclusiveLocks can conflict with lock types
     * that read-only transactions can acquire in a standby server.
     *
     * Make sure this definition matches the one in
     * GetRunningTransactionLocks().
     *
     * First we prepare to log, then after lock acquired we issue log record.
     */
    if (lockmode >= AccessExclusiveLock &&
        locktag->locktag_type == LOCKTAG_RELATION &&
        !RecoveryInProgress() &&
        XLogStandbyInfoActive())
    {
        LogAccessExclusiveLockPrepare();
        log_lock = true;
    }

    /*
     * Attempt to take lock via fast path, if eligible.  But if we remember
     * having filled up the fast path array, we don't attempt to make any
     * further use of it until we release some locks.  It's possible that some
     * other backend has transferred some of those locks to the shared hash
     * table, leaving space free, but it's not worth acquiring the LWLock just
     * to check.  It's also possible that we're acquiring a second or third
     * lock type on a relation we have already locked using the fast-path, but
     * for now we don't worry about that case either.
     */
    if (EligibleForRelationFastPath(locktag, lockmode)
        && FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND)
    {
        uint32      fasthashcode = FastPathStrongLockHashPartition(hashcode);
        bool        acquired;

        /*
         * LWLockAcquire acts as a memory sequencing point, so it's safe to
         * assume that any strong locker whose increment to
         * FastPathStrongRelationLocks->counts becomes visible after we test
         * it has yet to begin to transfer fast-path locks.
         */
        LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);
        if (FastPathStrongRelationLocks->count[fasthashcode] != 0)
            acquired = false;
        else
            acquired = FastPathGrantRelationLock(locktag->locktag_field2,
                                                 lockmode);
        LWLockRelease(MyProc->backendLock);
        if (acquired)
        {
            GrantLockLocal(locallock, owner);
            return LOCKACQUIRE_OK;
        }
    }

    /*
     * If this lock could potentially have been taken via the fast-path by
     * some other backend, we must (temporarily) disable further use of the
     * fast-path for this lock tag, and migrate any locks already taken via
     * this method to the main lock table.
     */
    if (ConflictsWithRelationFastPath(locktag, lockmode))
    {
        uint32      fasthashcode = FastPathStrongLockHashPartition(hashcode);

        BeginStrongLockAcquire(locallock, fasthashcode);
        if (!FastPathTransferRelationLocks(lockMethodTable, locktag,
                                           hashcode))
        {
            AbortStrongLockAcquire();
            if (reportMemoryError)
                ereport(ERROR,
                        (errcode(ERRCODE_OUT_OF_MEMORY),
                         errmsg("out of shared memory"),
                         errhint("You might need to increase max_locks_per_transaction.")));
            else
                return LOCKACQUIRE_NOT_AVAIL;
        }
    }

    /*
     * We didn't find the lock in our LOCALLOCK table, and we didn't manage to
     * take it via the fast-path, either, so we've got to mess with the shared
     * lock table.
     */
    partitionLock = LockHashPartitionLock(hashcode);

    LWLockAcquire(partitionLock, LW_EXCLUSIVE);

    /*
     * Find or create a proclock entry with this tag
     */
    proclock = SetupLockInTable(lockMethodTable, MyProc, locktag,
                                hashcode, lockmode);
    if (!proclock)
    {
        AbortStrongLockAcquire();
        LWLockRelease(partitionLock);
        if (reportMemoryError)
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of shared memory"),
                     errhint("You might need to increase max_locks_per_transaction.")));
        else
            return LOCKACQUIRE_NOT_AVAIL;
    }
    locallock->proclock = proclock;
    lock = proclock->tag.myLock;
    locallock->lock = lock;

    /*
     * If lock requested conflicts with locks requested by waiters, must join
     * wait queue.  Otherwise, check for conflict with already-held locks.
     * (That's last because most complex check.)
     */
    if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
        status = STATUS_FOUND;
    else
        status = LockCheckConflicts(lockMethodTable, lockmode,
                                    lock, proclock, MyProc);

    if (status == STATUS_OK)
    {
        /* No conflict with held or previously requested locks */
        GrantLock(lock, proclock, lockmode);
        GrantLockLocal(locallock, owner);
    }
    else
    {
        Assert(status == STATUS_FOUND);

        /*
         * We can't acquire the lock immediately.  If caller specified no
         * blocking, remove useless table entries and return NOT_AVAIL without
         * waiting.
         */
        if (dontWait)
        {
            AbortStrongLockAcquire();
            if (proclock->holdMask == 0)
            {
                uint32      proclock_hashcode;

                proclock_hashcode = ProcLockHashCode(&proclock->tag, hashcode);
                SHMQueueDelete(&proclock->lockLink);
                SHMQueueDelete(&proclock->procLink);
                if (!hash_search_with_hash_value(LockMethodProcLockHash,
                                                 (void *) &(proclock->tag),
                                                 proclock_hashcode,
                                                 HASH_REMOVE,
                                                 NULL))
                    elog(PANIC, "proclock table corrupted");
            }
            else
                PROCLOCK_PRINT("LockAcquire: NOWAIT", proclock);
            lock->nRequested--;
            lock->requested[lockmode]--;
            LOCK_PRINT("LockAcquire: conditional lock failed", lock, lockmode);
            Assert((lock->nRequested > 0) && (lock->requested[lockmode] >= 0));
            Assert(lock->nGranted <= lock->nRequested);
            LWLockRelease(partitionLock);
            if (locallock->nLocks == 0)
                RemoveLocalLock(locallock);
            return LOCKACQUIRE_NOT_AVAIL;
        }

        /*
         * Set bitmask of locks this process already holds on this object.
         */
        MyProc->heldLocks = proclock->holdMask;

        /*
         * Sleep till someone wakes me up.
         */

        TRACE_POSTGRESQL_LOCK_WAIT_START(locktag->locktag_field1,
                                         locktag->locktag_field2,
                                         locktag->locktag_field3,
                                         locktag->locktag_field4,
                                         locktag->locktag_type,
                                         lockmode);

        WaitOnLock(locallock, owner);

        TRACE_POSTGRESQL_LOCK_WAIT_DONE(locktag->locktag_field1,
                                        locktag->locktag_field2,
                                        locktag->locktag_field3,
                                        locktag->locktag_field4,
                                        locktag->locktag_type,
                                        lockmode);

        /*
         * NOTE: do not do any material change of state between here and
         * return.  All required changes in locktable state must have been
         * done when the lock was granted to us --- see notes in WaitOnLock.
         */

        /*
         * Check the proclock entry status, in case something in the ipc
         * communication doesn't work correctly.
         */
        if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
        {
            AbortStrongLockAcquire();
            PROCLOCK_PRINT("LockAcquire: INCONSISTENT", proclock);
            LOCK_PRINT("LockAcquire: INCONSISTENT", lock, lockmode);
            /* Should we retry ? */
            LWLockRelease(partitionLock);
            elog(ERROR, "LockAcquire failed");
        }
        PROCLOCK_PRINT("LockAcquire: granted", proclock);
        LOCK_PRINT("LockAcquire: granted", lock, lockmode);
    }

    /*
     * Lock state is fully up-to-date now; if we error out after this, no
     * special error cleanup is required.
     */
    FinishStrongLockAcquire();

    LWLockRelease(partitionLock);

    /*
     * Emit a WAL record if acquisition of this lock need to be replayed in a
     * standby server.
     */
    if (log_lock)
    {
        /*
         * Decode the locktag back to the original values, to avoid sending
         * lots of empty bytes with every message.  See lock.h to check how a
         * locktag is defined for LOCKTAG_RELATION
         */
        LogAccessExclusiveLock(locktag->locktag_field1,
                               locktag->locktag_field2);
    }

    return LOCKACQUIRE_OK;
}

int LockCheckConflicts ( LockMethod  lockMethodTable,
LOCKMODE  lockmode,
LOCK lock,
PROCLOCK proclock,
PGPROC proc 
)

Definition at line 1256 of file lock.c.

References LockMethodData::conflictTab, LOCK::granted, LOCK::grantMask, PROCLOCK::holdMask, i, LOCKBIT_ON, LockMethodData::numLockModes, and PROCLOCK_PRINT.

Referenced by LockAcquireExtended(), ProcLockWakeup(), and ProcSleep().

{
    int         numLockModes = lockMethodTable->numLockModes;
    LOCKMASK    myLocks;
    LOCKMASK    otherLocks;
    int         i;

    /*
     * first check for global conflicts: If no locks conflict with my request,
     * then I get the lock.
     *
     * Checking for conflict: lock->grantMask represents the types of
     * currently held locks.  conflictTable[lockmode] has a bit set for each
     * type of lock that conflicts with request.   Bitwise compare tells if
     * there is a conflict.
     */
    if (!(lockMethodTable->conflictTab[lockmode] & lock->grantMask))
    {
        PROCLOCK_PRINT("LockCheckConflicts: no conflict", proclock);
        return STATUS_OK;
    }

    /*
     * Rats.  Something conflicts.  But it could still be my own lock. We have
     * to construct a conflict mask that does not reflect our own locks, but
     * only lock types held by other processes.
     */
    myLocks = proclock->holdMask;
    otherLocks = 0;
    for (i = 1; i <= numLockModes; i++)
    {
        int         myHolding = (myLocks & LOCKBIT_ON(i)) ? 1 : 0;

        if (lock->granted[i] > myHolding)
            otherLocks |= LOCKBIT_ON(i);
    }

    /*
     * now check again for conflicts.  'otherLocks' describes the types of
     * locks held by other processes.  If one of these conflicts with the kind
     * of lock that I want, there is a conflict and I have to sleep.
     */
    if (!(lockMethodTable->conflictTab[lockmode] & otherLocks))
    {
        /* no conflict. OK to get the lock */
        PROCLOCK_PRINT("LockCheckConflicts: resolved", proclock);
        return STATUS_OK;
    }

    PROCLOCK_PRINT("LockCheckConflicts: conflicting", proclock);
    return STATUS_FOUND;
}

bool LockHasWaiters ( const LOCKTAG locktag,
LOCKMODE  lockmode,
bool  sessionLock 
)

Definition at line 560 of file lock.c.

References LockMethodData::conflictTab, elog, ERROR, hash_search(), LOCALLOCK::hashcode, PROCLOCK::holdMask, lengthof, LOCALLOCK::lock, LOCALLOCKTAG::lock, LOCK_PRINT, LOCKBIT_ON, LockHashPartitionLock, LockMethodData::lockModeNames, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_lockmethodid, LOG, LW_SHARED, LWLockAcquire(), LWLockRelease(), MemSet, LOCALLOCKTAG::mode, LOCALLOCK::nLocks, LockMethodData::numLockModes, LOCALLOCK::proclock, PROCLOCK_PRINT, RemoveLocalLock(), LOCK::waitMask, and WARNING.

Referenced by LockHasWaitersRelation().

{
    LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
    LockMethod  lockMethodTable;
    LOCALLOCKTAG localtag;
    LOCALLOCK  *locallock;
    LOCK       *lock;
    PROCLOCK   *proclock;
    LWLockId    partitionLock;
    bool        hasWaiters = false;

    if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
        elog(ERROR, "unrecognized lock method: %d", lockmethodid);
    lockMethodTable = LockMethods[lockmethodid];
    if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
        elog(ERROR, "unrecognized lock mode: %d", lockmode);

#ifdef LOCK_DEBUG
    if (LOCK_DEBUG_ENABLED(locktag))
        elog(LOG, "LockHasWaiters: lock [%u,%u] %s",
             locktag->locktag_field1, locktag->locktag_field2,
             lockMethodTable->lockModeNames[lockmode]);
#endif

    /*
     * Find the LOCALLOCK entry for this lock and lockmode
     */
    MemSet(&localtag, 0, sizeof(localtag));     /* must clear padding */
    localtag.lock = *locktag;
    localtag.mode = lockmode;

    locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
                                          (void *) &localtag,
                                          HASH_FIND, NULL);

    /*
     * let the caller print its own error message, too. Do not ereport(ERROR).
     */
    if (!locallock || locallock->nLocks <= 0)
    {
        elog(WARNING, "you don't own a lock of type %s",
             lockMethodTable->lockModeNames[lockmode]);
        return false;
    }

    /*
     * Check the shared lock table.
     */
    partitionLock = LockHashPartitionLock(locallock->hashcode);

    LWLockAcquire(partitionLock, LW_SHARED);

    /*
     * We don't need to re-find the lock or proclock, since we kept their
     * addresses in the locallock table, and they couldn't have been removed
     * while we were holding a lock on them.
     */
    lock = locallock->lock;
    LOCK_PRINT("LockHasWaiters: found", lock, lockmode);
    proclock = locallock->proclock;
    PROCLOCK_PRINT("LockHasWaiters: found", proclock);

    /*
     * Double-check that we are actually holding a lock of the type we want to
     * release.
     */
    if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
    {
        PROCLOCK_PRINT("LockHasWaiters: WRONGTYPE", proclock);
        LWLockRelease(partitionLock);
        elog(WARNING, "you don't own a lock of type %s",
             lockMethodTable->lockModeNames[lockmode]);
        RemoveLocalLock(locallock);
        return false;
    }

    /*
     * Do the checking.
     */
    if ((lockMethodTable->conflictTab[lockmode] & lock->waitMask) != 0)
        hasWaiters = true;

    LWLockRelease(partitionLock);

    return hasWaiters;
}

void LockReassignCurrentOwner ( LOCALLOCK **  locallocks,
int  nlocks 
)

Definition at line 2298 of file lock.c.

References Assert, CurrentResourceOwner, hash_seq_init(), hash_seq_search(), i, LockReassignOwner(), NULL, and ResourceOwnerGetParent().

Referenced by ResourceOwnerReleaseInternal().

{
    ResourceOwner parent = ResourceOwnerGetParent(CurrentResourceOwner);

    Assert(parent != NULL);

    if (locallocks == NULL)
    {
        HASH_SEQ_STATUS status;
        LOCALLOCK  *locallock;

        hash_seq_init(&status, LockMethodLocalHash);

        while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
            LockReassignOwner(locallock, parent);
    }
    else
    {
        int i;

        for (i = nlocks - 1; i >= 0; i--)
            LockReassignOwner(locallocks[i], parent);
    }
}

static void LockReassignOwner ( LOCALLOCK locallock,
ResourceOwner  parent 
) [static]

Definition at line 2328 of file lock.c.

References CurrentResourceOwner, i, LOCALLOCK::lockOwners, LOCALLOCKOWNER::nLocks, LOCALLOCK::numLockOwners, LOCALLOCKOWNER::owner, ResourceOwnerForgetLock(), and ResourceOwnerRememberLock().

Referenced by LockReassignCurrentOwner().

{
    LOCALLOCKOWNER *lockOwners;
    int         i;
    int         ic = -1;
    int         ip = -1;

    /*
     * Scan to see if there are any locks belonging to current owner or
     * its parent
     */
    lockOwners = locallock->lockOwners;
    for (i = locallock->numLockOwners - 1; i >= 0; i--)
    {
        if (lockOwners[i].owner == CurrentResourceOwner)
            ic = i;
        else if (lockOwners[i].owner == parent)
            ip = i;
    }

    if (ic < 0)
        return;         /* no current locks */

    if (ip < 0)
    {
        /* Parent has no slot, so just give it the child's slot */
        lockOwners[ic].owner = parent;
        ResourceOwnerRememberLock(parent, locallock);
    }
    else
    {
        /* Merge child's count with parent's */
        lockOwners[ip].nLocks += lockOwners[ic].nLocks;
        /* compact out unused slot */
        locallock->numLockOwners--;
        if (ic < locallock->numLockOwners)
            lockOwners[ic] = lockOwners[locallock->numLockOwners];
    }
    ResourceOwnerForgetLock(CurrentResourceOwner, locallock);
}

static void LockRefindAndRelease ( LockMethod  lockMethodTable,
PGPROC proc,
LOCKTAG locktag,
LOCKMODE  lockmode,
bool  decrement_strong_lock_count 
) [static]

Definition at line 2830 of file lock.c.

References CleanUpLock(), ConflictsWithRelationFastPath, FastPathStrongRelationLockData::count, elog, FastPathStrongLockHashPartition, hash_search_with_hash_value(), PROCLOCK::holdMask, LOCKBIT_ON, LockHashPartitionLock, LockMethodData::lockModeNames, LockTagHashCode(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), FastPathStrongRelationLockData::mutex, PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, PANIC, PROCLOCK_PRINT, ProcLockHashCode(), SpinLockAcquire, SpinLockRelease, LOCK::tag, UnGrantLock(), and WARNING.

Referenced by lock_twophase_postcommit(), LockReleaseAll(), and VirtualXactLockTableCleanup().

{
    LOCK       *lock;
    PROCLOCK   *proclock;
    PROCLOCKTAG proclocktag;
    uint32      hashcode;
    uint32      proclock_hashcode;
    LWLockId    partitionLock;
    bool        wakeupNeeded;

    hashcode = LockTagHashCode(locktag);
    partitionLock = LockHashPartitionLock(hashcode);

    LWLockAcquire(partitionLock, LW_EXCLUSIVE);

    /*
     * Re-find the lock object (it had better be there).
     */
    lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
                                                (void *) locktag,
                                                hashcode,
                                                HASH_FIND,
                                                NULL);
    if (!lock)
        elog(PANIC, "failed to re-find shared lock object");

    /*
     * Re-find the proclock object (ditto).
     */
    proclocktag.myLock = lock;
    proclocktag.myProc = proc;

    proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);

    proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,
                                                        (void *) &proclocktag,
                                                        proclock_hashcode,
                                                        HASH_FIND,
                                                        NULL);
    if (!proclock)
        elog(PANIC, "failed to re-find shared proclock object");

    /*
     * Double-check that we are actually holding a lock of the type we want to
     * release.
     */
    if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
    {
        PROCLOCK_PRINT("lock_twophase_postcommit: WRONGTYPE", proclock);
        LWLockRelease(partitionLock);
        elog(WARNING, "you don't own a lock of type %s",
             lockMethodTable->lockModeNames[lockmode]);
        return;
    }

    /*
     * Do the releasing.  CleanUpLock will waken any now-wakable waiters.
     */
    wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);

    CleanUpLock(lock, proclock,
                lockMethodTable, hashcode,
                wakeupNeeded);

    LWLockRelease(partitionLock);

    /*
     * Decrement strong lock count.  This logic is needed only for 2PC.
     */
    if (decrement_strong_lock_count
        && ConflictsWithRelationFastPath(&lock->tag, lockmode))
    {
        uint32      fasthashcode = FastPathStrongLockHashPartition(hashcode);

        SpinLockAcquire(&FastPathStrongRelationLocks->mutex);
        FastPathStrongRelationLocks->count[fasthashcode]--;
        SpinLockRelease(&FastPathStrongRelationLocks->mutex);
    }
}

bool LockRelease ( const LOCKTAG locktag,
LOCKMODE  lockmode,
bool  sessionLock 
)

Definition at line 1730 of file lock.c.

References Assert, PGPROC::backendLock, CleanUpLock(), CurrentResourceOwner, EligibleForRelationFastPath, elog, ERROR, FastPathLocalUseCount, FastPathUnGrantRelationLock(), hash_search(), hash_search_with_hash_value(), LOCALLOCK::hashcode, PROCLOCK::holdMask, i, lengthof, LOCALLOCK::lock, LOCALLOCKTAG::lock, LOCK_PRINT, LOCKBIT_ON, LockHashPartitionLock, LockMethodData::lockModeNames, LOCALLOCK::lockOwners, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_lockmethodid, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MemSet, LOCALLOCKTAG::mode, PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, MyProc, LOCALLOCK::nLocks, NULL, LockMethodData::numLockModes, LOCALLOCK::numLockOwners, LOCALLOCK::proclock, PROCLOCK_PRINT, RemoveLocalLock(), ResourceOwnerForgetLock(), UnGrantLock(), and WARNING.

Referenced by ConditionalXactLockTableWait(), pg_advisory_unlock_int4(), pg_advisory_unlock_int8(), pg_advisory_unlock_shared_int4(), pg_advisory_unlock_shared_int8(), ReleaseLockIfHeld(), StandbyReleaseAllLocks(), StandbyReleaseLocks(), StandbyReleaseOldLocks(), UnlockDatabaseObject(), UnlockPage(), UnlockRelation(), UnlockRelationForExtension(), UnlockRelationId(), UnlockRelationIdForSession(), UnlockRelationOid(), UnlockSharedObject(), UnlockSharedObjectForSession(), UnlockTuple(), VirtualXactLock(), XactLockTableDelete(), and XactLockTableWait().

{
    LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
    LockMethod  lockMethodTable;
    LOCALLOCKTAG localtag;
    LOCALLOCK  *locallock;
    LOCK       *lock;
    PROCLOCK   *proclock;
    LWLockId    partitionLock;
    bool        wakeupNeeded;

    if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
        elog(ERROR, "unrecognized lock method: %d", lockmethodid);
    lockMethodTable = LockMethods[lockmethodid];
    if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
        elog(ERROR, "unrecognized lock mode: %d", lockmode);

#ifdef LOCK_DEBUG
    if (LOCK_DEBUG_ENABLED(locktag))
        elog(LOG, "LockRelease: lock [%u,%u] %s",
             locktag->locktag_field1, locktag->locktag_field2,
             lockMethodTable->lockModeNames[lockmode]);
#endif

    /*
     * Find the LOCALLOCK entry for this lock and lockmode
     */
    MemSet(&localtag, 0, sizeof(localtag));     /* must clear padding */
    localtag.lock = *locktag;
    localtag.mode = lockmode;

    locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
                                          (void *) &localtag,
                                          HASH_FIND, NULL);

    /*
     * let the caller print its own error message, too. Do not ereport(ERROR).
     */
    if (!locallock || locallock->nLocks <= 0)
    {
        elog(WARNING, "you don't own a lock of type %s",
             lockMethodTable->lockModeNames[lockmode]);
        return FALSE;
    }

    /*
     * Decrease the count for the resource owner.
     */
    {
        LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
        ResourceOwner owner;
        int         i;

        /* Identify owner for lock */
        if (sessionLock)
            owner = NULL;
        else
            owner = CurrentResourceOwner;

        for (i = locallock->numLockOwners - 1; i >= 0; i--)
        {
            if (lockOwners[i].owner == owner)
            {
                Assert(lockOwners[i].nLocks > 0);
                if (--lockOwners[i].nLocks == 0)
                {
                    if (owner != NULL)
                        ResourceOwnerForgetLock(owner, locallock);
                    /* compact out unused slot */
                    locallock->numLockOwners--;
                    if (i < locallock->numLockOwners)
                        lockOwners[i] = lockOwners[locallock->numLockOwners];
                }
                break;
            }
        }
        if (i < 0)
        {
            /* don't release a lock belonging to another owner */
            elog(WARNING, "you don't own a lock of type %s",
                 lockMethodTable->lockModeNames[lockmode]);
            return FALSE;
        }
    }

    /*
     * Decrease the total local count.  If we're still holding the lock, we're
     * done.
     */
    locallock->nLocks--;

    if (locallock->nLocks > 0)
        return TRUE;

    /* Attempt fast release of any lock eligible for the fast path. */
    if (EligibleForRelationFastPath(locktag, lockmode)
        && FastPathLocalUseCount > 0)
    {
        bool        released;

        /*
         * We might not find the lock here, even if we originally entered it
         * here.  Another backend may have moved it to the main table.
         */
        LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);
        released = FastPathUnGrantRelationLock(locktag->locktag_field2,
                                               lockmode);
        LWLockRelease(MyProc->backendLock);
        if (released)
        {
            RemoveLocalLock(locallock);
            return TRUE;
        }
    }

    /*
     * Otherwise we've got to mess with the shared lock table.
     */
    partitionLock = LockHashPartitionLock(locallock->hashcode);

    LWLockAcquire(partitionLock, LW_EXCLUSIVE);

    /*
     * Normally, we don't need to re-find the lock or proclock, since we kept
     * their addresses in the locallock table, and they couldn't have been
     * removed while we were holding a lock on them.  But it's possible that
     * the locks have been moved to the main hash table by another backend, in
     * which case we might need to go look them up after all.
     */
    lock = locallock->lock;
    if (!lock)
    {
        PROCLOCKTAG proclocktag;
        bool        found;

        Assert(EligibleForRelationFastPath(locktag, lockmode));
        lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
                                                    (const void *) locktag,
                                                    locallock->hashcode,
                                                    HASH_FIND,
                                                    &found);
        Assert(found && lock != NULL);
        locallock->lock = lock;

        proclocktag.myLock = lock;
        proclocktag.myProc = MyProc;
        locallock->proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
                                                       (void *) &proclocktag,
                                                       HASH_FIND, &found);
        Assert(found);
    }
    LOCK_PRINT("LockRelease: found", lock, lockmode);
    proclock = locallock->proclock;
    PROCLOCK_PRINT("LockRelease: found", proclock);

    /*
     * Double-check that we are actually holding a lock of the type we want to
     * release.
     */
    if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
    {
        PROCLOCK_PRINT("LockRelease: WRONGTYPE", proclock);
        LWLockRelease(partitionLock);
        elog(WARNING, "you don't own a lock of type %s",
             lockMethodTable->lockModeNames[lockmode]);
        RemoveLocalLock(locallock);
        return FALSE;
    }

    /*
     * Do the releasing.  CleanUpLock will waken any now-wakable waiters.
     */
    wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);

    CleanUpLock(lock, proclock,
                lockMethodTable, locallock->hashcode,
                wakeupNeeded);

    LWLockRelease(partitionLock);

    RemoveLocalLock(locallock);
    return TRUE;
}

void LockReleaseAll ( LOCKMETHODID  lockmethodid,
bool  allLocks 
)

Definition at line 1923 of file lock.c.

References Assert, PGPROC::backendLock, CleanUpLock(), DEFAULT_LOCKMETHOD, EligibleForRelationFastPath, elog, ERROR, FastPathUnGrantRelationLock(), FirstLockMgrLock, LOCK::grantMask, hash_seq_init(), hash_seq_search(), PROCLOCK::holdMask, i, lengthof, LOCALLOCK_LOCKMETHOD, LOCALLOCKTAG::lock, LOCALLOCK::lock, LOCK_LOCKMETHOD, LOCK_PRINT, LOCKBIT_ON, LOCALLOCK::lockOwners, LockRefindAndRelease(), LOCKTAG::locktag_field2, LockTagHashCode(), LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), LOCALLOCKTAG::mode, PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, MyProc, PGPROC::myProcLocks, LOCK::nGranted, LOCALLOCKOWNER::nLocks, LOCALLOCK::nLocks, LOCK::nRequested, NULL, LockMethodData::numLockModes, LOCALLOCK::numLockOwners, offsetof, LOCALLOCKOWNER::owner, PANIC, PROCLOCK::procLink, LOCALLOCK::proclock, PROCLOCK_PRINT, PROCLOCK::releaseMask, RemoveLocalLock(), ResourceOwnerForgetLock(), SHMQueueNext(), LOCK::tag, PROCLOCK::tag, LOCALLOCK::tag, LockMethodData::trace_flag, UnGrantLock(), and VirtualXactLockTableCleanup().

Referenced by DiscardAll(), ProcReleaseLocks(), and ShutdownPostgres().

{
    HASH_SEQ_STATUS status;
    LockMethod  lockMethodTable;
    int         i,
                numLockModes;
    LOCALLOCK  *locallock;
    LOCK       *lock;
    PROCLOCK   *proclock;
    int         partition;
    bool        have_fast_path_lwlock = false;

    if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
        elog(ERROR, "unrecognized lock method: %d", lockmethodid);
    lockMethodTable = LockMethods[lockmethodid];

#ifdef LOCK_DEBUG
    if (*(lockMethodTable->trace_flag))
        elog(LOG, "LockReleaseAll: lockmethod=%d", lockmethodid);
#endif

    /*
     * Get rid of our fast-path VXID lock, if appropriate.  Note that this is
     * the only way that the lock we hold on our own VXID can ever get
     * released: it is always and only released when a toplevel transaction
     * ends.
     */
    if (lockmethodid == DEFAULT_LOCKMETHOD)
        VirtualXactLockTableCleanup();

    numLockModes = lockMethodTable->numLockModes;

    /*
     * First we run through the locallock table and get rid of unwanted
     * entries, then we scan the process's proclocks and get rid of those. We
     * do this separately because we may have multiple locallock entries
     * pointing to the same proclock, and we daren't end up with any dangling
     * pointers.
     */
    hash_seq_init(&status, LockMethodLocalHash);

    while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
    {
        /*
         * If the LOCALLOCK entry is unused, we must've run out of shared
         * memory while trying to set up this lock.  Just forget the local
         * entry.
         */
        if (locallock->nLocks == 0)
        {
            RemoveLocalLock(locallock);
            continue;
        }

        /* Ignore items that are not of the lockmethod to be removed */
        if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)
            continue;

        /*
         * If we are asked to release all locks, we can just zap the entry.
         * Otherwise, must scan to see if there are session locks. We assume
         * there is at most one lockOwners entry for session locks.
         */
        if (!allLocks)
        {
            LOCALLOCKOWNER *lockOwners = locallock->lockOwners;

            /* If session lock is above array position 0, move it down to 0 */
            for (i = 0; i < locallock->numLockOwners ; i++)
            {
                if (lockOwners[i].owner == NULL)
                    lockOwners[0] = lockOwners[i];
                else
                    ResourceOwnerForgetLock(lockOwners[i].owner, locallock);
            }

            if (locallock->numLockOwners > 0 &&
                lockOwners[0].owner == NULL &&
                lockOwners[0].nLocks > 0)
            {
                /* Fix the locallock to show just the session locks */
                locallock->nLocks = lockOwners[0].nLocks;
                locallock->numLockOwners = 1;
                /* We aren't deleting this locallock, so done */
                continue;
            }
            else
                locallock->numLockOwners = 0;
        }

        /*
         * If the lock or proclock pointers are NULL, this lock was taken via
         * the relation fast-path.
         */
        if (locallock->proclock == NULL || locallock->lock == NULL)
        {
            LOCKMODE    lockmode = locallock->tag.mode;
            Oid         relid;

            /* Verify that a fast-path lock is what we've got. */
            if (!EligibleForRelationFastPath(&locallock->tag.lock, lockmode))
                elog(PANIC, "locallock table corrupted");

            /*
             * If we don't currently hold the LWLock that protects our
             * fast-path data structures, we must acquire it before attempting
             * to release the lock via the fast-path.
             */
            if (!have_fast_path_lwlock)
            {
                LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);
                have_fast_path_lwlock = true;
            }

            /* Attempt fast-path release. */
            relid = locallock->tag.lock.locktag_field2;
            if (FastPathUnGrantRelationLock(relid, lockmode))
            {
                RemoveLocalLock(locallock);
                continue;
            }

            /*
             * Our lock, originally taken via the fast path, has been
             * transferred to the main lock table.  That's going to require
             * some extra work, so release our fast-path lock before starting.
             */
            LWLockRelease(MyProc->backendLock);
            have_fast_path_lwlock = false;

            /*
             * Now dump the lock.  We haven't got a pointer to the LOCK or
             * PROCLOCK in this case, so we have to handle this a bit
             * differently than a normal lock release.  Unfortunately, this
             * requires an extra LWLock acquire-and-release cycle on the
             * partitionLock, but hopefully it shouldn't happen often.
             */
            LockRefindAndRelease(lockMethodTable, MyProc,
                                 &locallock->tag.lock, lockmode, false);
            RemoveLocalLock(locallock);
            continue;
        }

        /* Mark the proclock to show we need to release this lockmode */
        if (locallock->nLocks > 0)
            locallock->proclock->releaseMask |= LOCKBIT_ON(locallock->tag.mode);

        /* And remove the locallock hashtable entry */
        RemoveLocalLock(locallock);
    }

    if (have_fast_path_lwlock)
        LWLockRelease(MyProc->backendLock);

    /*
     * Now, scan each lock partition separately.
     */
    for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)
    {
        LWLockId    partitionLock = FirstLockMgrLock + partition;
        SHM_QUEUE  *procLocks = &(MyProc->myProcLocks[partition]);

        proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
                                             offsetof(PROCLOCK, procLink));

        if (!proclock)
            continue;           /* needn't examine this partition */

        LWLockAcquire(partitionLock, LW_EXCLUSIVE);

        while (proclock)
        {
            bool        wakeupNeeded = false;
            PROCLOCK   *nextplock;

            /* Get link first, since we may unlink/delete this proclock */
            nextplock = (PROCLOCK *)
                SHMQueueNext(procLocks, &proclock->procLink,
                             offsetof(PROCLOCK, procLink));

            Assert(proclock->tag.myProc == MyProc);

            lock = proclock->tag.myLock;

            /* Ignore items that are not of the lockmethod to be removed */
            if (LOCK_LOCKMETHOD(*lock) != lockmethodid)
                goto next_item;

            /*
             * In allLocks mode, force release of all locks even if locallock
             * table had problems
             */
            if (allLocks)
                proclock->releaseMask = proclock->holdMask;
            else
                Assert((proclock->releaseMask & ~proclock->holdMask) == 0);

            /*
             * Ignore items that have nothing to be released, unless they have
             * holdMask == 0 and are therefore recyclable
             */
            if (proclock->releaseMask == 0 && proclock->holdMask != 0)
                goto next_item;

            PROCLOCK_PRINT("LockReleaseAll", proclock);
            LOCK_PRINT("LockReleaseAll", lock, 0);
            Assert(lock->nRequested >= 0);
            Assert(lock->nGranted >= 0);
            Assert(lock->nGranted <= lock->nRequested);
            Assert((proclock->holdMask & ~lock->grantMask) == 0);

            /*
             * Release the previously-marked lock modes
             */
            for (i = 1; i <= numLockModes; i++)
            {
                if (proclock->releaseMask & LOCKBIT_ON(i))
                    wakeupNeeded |= UnGrantLock(lock, i, proclock,
                                                lockMethodTable);
            }
            Assert((lock->nRequested >= 0) && (lock->nGranted >= 0));
            Assert(lock->nGranted <= lock->nRequested);
            LOCK_PRINT("LockReleaseAll: updated", lock, 0);

            proclock->releaseMask = 0;

            /* CleanUpLock will wake up waiters if needed. */
            CleanUpLock(lock, proclock,
                        lockMethodTable,
                        LockTagHashCode(&lock->tag),
                        wakeupNeeded);

    next_item:
            proclock = nextplock;
        }                       /* loop over PROCLOCKs within this partition */

        LWLockRelease(partitionLock);
    }                           /* loop over partitions */

#ifdef LOCK_DEBUG
    if (*(lockMethodTable->trace_flag))
        elog(LOG, "LockReleaseAll done");
#endif
}

void LockReleaseCurrentOwner ( LOCALLOCK **  locallocks,
int  nlocks 
)

Definition at line 2203 of file lock.c.

References hash_seq_init(), hash_seq_search(), i, NULL, and ReleaseLockIfHeld().

Referenced by ResourceOwnerReleaseInternal().

{
    if (locallocks == NULL)
    {
        HASH_SEQ_STATUS status;
        LOCALLOCK  *locallock;

        hash_seq_init(&status, LockMethodLocalHash);

        while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
            ReleaseLockIfHeld(locallock, false);
    }
    else
    {
        int i;

        for (i = nlocks - 1; i >= 0; i--)
            ReleaseLockIfHeld(locallocks[i], false);
    }
}

void LockReleaseSession ( LOCKMETHODID  lockmethodid  ) 

Definition at line 2173 of file lock.c.

References elog, ERROR, hash_seq_init(), hash_seq_search(), lengthof, LOCALLOCK_LOCKMETHOD, NULL, and ReleaseLockIfHeld().

Referenced by pg_advisory_unlock_all().

{
    HASH_SEQ_STATUS status;
    LOCALLOCK  *locallock;

    if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
        elog(ERROR, "unrecognized lock method: %d", lockmethodid);

    hash_seq_init(&status, LockMethodLocalHash);

    while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
    {
        /* Ignore items that are not of the specified lock method */
        if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)
            continue;

        ReleaseLockIfHeld(locallock, true);
    }
}

Size LockShmemSize ( void   ) 

Definition at line 3210 of file lock.c.

References add_size(), hash_estimate_size(), and NLOCKENTS.

Referenced by CreateSharedMemoryAndSemaphores().

{
    Size        size = 0;
    long        max_table_size;

    /* lock hash table */
    max_table_size = NLOCKENTS();
    size = add_size(size, hash_estimate_size(max_table_size, sizeof(LOCK)));

    /* proclock hash table */
    max_table_size *= 2;
    size = add_size(size, hash_estimate_size(max_table_size, sizeof(PROCLOCK)));

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

    return size;
}

uint32 LockTagHashCode ( const LOCKTAG locktag  ) 
void PostPrepare_Locks ( TransactionId  xid  ) 

Definition at line 3036 of file lock.c.

References Assert, elog, END_CRIT_SECTION, ereport, errcode(), errmsg(), FirstLockMgrLock, LOCK::grantMask, hash_seq_init(), hash_seq_search(), hash_update_hash_key(), PROCLOCK::holdMask, i, LOCALLOCKTAG::lock, LOCALLOCK::lock, LOCK_PRINT, LOCKBIT_ON, LOCALLOCK::lockOwners, LOCKTAG::locktag_type, LOCKTAG_VIRTUALTRANSACTION, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), LOCALLOCKTAG::mode, PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, MyProc, PGPROC::myProcLocks, LOCK::nGranted, LOCALLOCK::nLocks, LOCK::nRequested, NULL, LOCALLOCK::numLockOwners, offsetof, PANIC, PROCLOCK::procLink, LOCALLOCK::proclock, PROCLOCK_PRINT, PROCLOCK::releaseMask, RemoveLocalLock(), SHMQueueDelete(), SHMQueueInsertBefore(), SHMQueueNext(), START_CRIT_SECTION, LOCK::tag, PROCLOCK::tag, LOCALLOCK::tag, and TwoPhaseGetDummyProc().

Referenced by PrepareTransaction().

{
    PGPROC     *newproc = TwoPhaseGetDummyProc(xid);
    HASH_SEQ_STATUS status;
    LOCALLOCK  *locallock;
    LOCK       *lock;
    PROCLOCK   *proclock;
    PROCLOCKTAG proclocktag;
    int         partition;

    /* This is a critical section: any error means big trouble */
    START_CRIT_SECTION();

    /*
     * First we run through the locallock table and get rid of unwanted
     * entries, then we scan the process's proclocks and transfer them to the
     * target proc.
     *
     * We do this separately because we may have multiple locallock entries
     * pointing to the same proclock, and we daren't end up with any dangling
     * pointers.
     */
    hash_seq_init(&status, LockMethodLocalHash);

    while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
    {
        LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
        bool        haveSessionLock;
        bool        haveXactLock;
        int         i;

        if (locallock->proclock == NULL || locallock->lock == NULL)
        {
            /*
             * We must've run out of shared memory while trying to set up this
             * lock.  Just forget the local entry.
             */
            Assert(locallock->nLocks == 0);
            RemoveLocalLock(locallock);
            continue;
        }

        /* Ignore VXID locks */
        if (locallock->tag.lock.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
            continue;

        /* Scan to see whether we hold it at session or transaction level */
        haveSessionLock = haveXactLock = false;
        for (i = locallock->numLockOwners - 1; i >= 0; i--)
        {
            if (lockOwners[i].owner == NULL)
                haveSessionLock = true;
            else
                haveXactLock = true;
        }

        /* Ignore it if we have only session lock */
        if (!haveXactLock)
            continue;

        /* This can't happen, because we already checked it */
        if (haveSessionLock)
            ereport(PANIC,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("cannot PREPARE while holding both session-level and transaction-level locks on the same object")));

        /* Mark the proclock to show we need to release this lockmode */
        if (locallock->nLocks > 0)
            locallock->proclock->releaseMask |= LOCKBIT_ON(locallock->tag.mode);

        /* And remove the locallock hashtable entry */
        RemoveLocalLock(locallock);
    }

    /*
     * Now, scan each lock partition separately.
     */
    for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)
    {
        LWLockId    partitionLock = FirstLockMgrLock + partition;
        SHM_QUEUE  *procLocks = &(MyProc->myProcLocks[partition]);

        proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
                                             offsetof(PROCLOCK, procLink));

        if (!proclock)
            continue;           /* needn't examine this partition */

        LWLockAcquire(partitionLock, LW_EXCLUSIVE);

        while (proclock)
        {
            PROCLOCK   *nextplock;

            /* Get link first, since we may unlink/relink this proclock */
            nextplock = (PROCLOCK *)
                SHMQueueNext(procLocks, &proclock->procLink,
                             offsetof(PROCLOCK, procLink));

            Assert(proclock->tag.myProc == MyProc);

            lock = proclock->tag.myLock;

            /* Ignore VXID locks */
            if (lock->tag.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
                goto next_item;

            PROCLOCK_PRINT("PostPrepare_Locks", proclock);
            LOCK_PRINT("PostPrepare_Locks", lock, 0);
            Assert(lock->nRequested >= 0);
            Assert(lock->nGranted >= 0);
            Assert(lock->nGranted <= lock->nRequested);
            Assert((proclock->holdMask & ~lock->grantMask) == 0);

            /* Ignore it if nothing to release (must be a session lock) */
            if (proclock->releaseMask == 0)
                goto next_item;

            /* Else we should be releasing all locks */
            if (proclock->releaseMask != proclock->holdMask)
                elog(PANIC, "we seem to have dropped a bit somewhere");

            /*
             * We cannot simply modify proclock->tag.myProc to reassign
             * ownership of the lock, because that's part of the hash key and
             * the proclock would then be in the wrong hash chain.  Instead
             * use hash_update_hash_key.  (We used to create a new hash entry,
             * but that risks out-of-memory failure if other processes are
             * busy making proclocks too.)  We must unlink the proclock from
             * our procLink chain and put it into the new proc's chain, too.
             *
             * Note: the updated proclock hash key will still belong to the
             * same hash partition, cf proclock_hash().  So the partition
             * lock we already hold is sufficient for this.
             */
            SHMQueueDelete(&proclock->procLink);

            /*
             * Create the new hash key for the proclock.
             */
            proclocktag.myLock = lock;
            proclocktag.myProc = newproc;

            /*
             * Update the proclock.  We should not find any existing entry
             * for the same hash key, since there can be only one entry for
             * any given lock with my own proc.
             */
            if (!hash_update_hash_key(LockMethodProcLockHash,
                                      (void *) proclock,
                                      (void *) &proclocktag))
                elog(PANIC, "duplicate entry found while reassigning a prepared transaction's locks");

            /* Re-link into the new proc's proclock list */
            SHMQueueInsertBefore(&(newproc->myProcLocks[partition]),
                                 &proclock->procLink);

            PROCLOCK_PRINT("PostPrepare_Locks: updated", proclock);

    next_item:
            proclock = nextplock;
        }                       /* loop over PROCLOCKs within this partition */

        LWLockRelease(partitionLock);
    }                           /* loop over partitions */

    END_CRIT_SECTION();
}

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

Definition at line 496 of file lock.c.

References Assert, LockTagHashCode(), PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, PointerGetDatum, and LOCK::tag.

{
    const PROCLOCKTAG *proclocktag = (const PROCLOCKTAG *) key;
    uint32      lockhash;
    Datum       procptr;

    Assert(keysize == sizeof(PROCLOCKTAG));

    /* Look into the associated LOCK object, and compute its hash code */
    lockhash = LockTagHashCode(&proclocktag->myLock->tag);

    /*
     * To make the hash code also depend on the PGPROC, we xor the proc
     * struct's address into the hash code, left-shifted so that the
     * partition-number bits don't change.  Since this is only a hash, we
     * don't care if we lose high-order bits of the address; use an
     * intermediate variable to suppress cast-pointer-to-int warnings.
     */
    procptr = PointerGetDatum(proclocktag->myProc);
    lockhash ^= ((uint32) procptr) << LOG2_NUM_LOCK_PARTITIONS;

    return lockhash;
}

static uint32 ProcLockHashCode ( const PROCLOCKTAG proclocktag,
uint32  hashcode 
) [inline, static]

Definition at line 527 of file lock.c.

References PROCLOCKTAG::myProc, and PointerGetDatum.

Referenced by CleanUpLock(), FastPathGetRelationLockEntry(), lock_twophase_recover(), LockAcquireExtended(), LockRefindAndRelease(), and SetupLockInTable().

{
    uint32      lockhash = hashcode;
    Datum       procptr;

    /*
     * This must match proclock_hash()!
     */
    procptr = PointerGetDatum(proclocktag->myProc);
    lockhash ^= ((uint32) procptr) << LOG2_NUM_LOCK_PARTITIONS;

    return lockhash;
}

static void ReleaseLockIfHeld ( LOCALLOCK locallock,
bool  sessionLock 
) [static]

Definition at line 2238 of file lock.c.

References Assert, CurrentResourceOwner, elog, i, LOCALLOCKTAG::lock, LOCALLOCK::lockOwners, LockRelease(), LOCALLOCKTAG::mode, LOCALLOCKOWNER::nLocks, LOCALLOCK::nLocks, NULL, LOCALLOCK::numLockOwners, ResourceOwnerForgetLock(), LOCALLOCK::tag, and WARNING.

Referenced by LockReleaseCurrentOwner(), and LockReleaseSession().

{
    ResourceOwner owner;
    LOCALLOCKOWNER *lockOwners;
    int         i;

    /* Identify owner for lock (must match LockRelease!) */
    if (sessionLock)
        owner = NULL;
    else
        owner = CurrentResourceOwner;

    /* Scan to see if there are any locks belonging to the target owner */
    lockOwners = locallock->lockOwners;
    for (i = locallock->numLockOwners - 1; i >= 0; i--)
    {
        if (lockOwners[i].owner == owner)
        {
            Assert(lockOwners[i].nLocks > 0);
            if (lockOwners[i].nLocks < locallock->nLocks)
            {
                /*
                 * We will still hold this lock after forgetting this
                 * ResourceOwner.
                 */
                locallock->nLocks -= lockOwners[i].nLocks;
                /* compact out unused slot */
                locallock->numLockOwners--;
                if (owner != NULL)
                    ResourceOwnerForgetLock(owner, locallock);
                if (i < locallock->numLockOwners)
                    lockOwners[i] = lockOwners[locallock->numLockOwners];
            }
            else
            {
                Assert(lockOwners[i].nLocks == locallock->nLocks);
                /* We want to call LockRelease just once */
                lockOwners[i].nLocks = 1;
                locallock->nLocks = 1;
                if (!LockRelease(&locallock->tag.lock,
                                 locallock->tag.mode,
                                 sessionLock))
                    elog(WARNING, "ReleaseLockIfHeld: failed??");
            }
            break;
        }
    }
}

void RemoveFromWaitQueue ( PGPROC proc,
uint32  hashcode 
)

Definition at line 1673 of file lock.c.

References Assert, CleanUpLock(), LOCK::granted, lengthof, PGPROC::links, LOCK_LOCKMETHOD, LOCKBIT_OFF, SHM_QUEUE::next, LOCK::nGranted, LOCK::nRequested, NULL, LOCK::requested, SHMQueueDelete(), PROC_QUEUE::size, STATUS_WAITING, PGPROC::waitLock, PGPROC::waitLockMode, LOCK::waitMask, PGPROC::waitProcLock, LOCK::waitProcs, and PGPROC::waitStatus.

Referenced by CheckDeadLock(), LockErrorCleanup(), and ProcSleep().

{
    LOCK       *waitLock = proc->waitLock;
    PROCLOCK   *proclock = proc->waitProcLock;
    LOCKMODE    lockmode = proc->waitLockMode;
    LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*waitLock);

    /* Make sure proc is waiting */
    Assert(proc->waitStatus == STATUS_WAITING);
    Assert(proc->links.next != NULL);
    Assert(waitLock);
    Assert(waitLock->waitProcs.size > 0);
    Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));

    /* Remove proc from lock's wait queue */
    SHMQueueDelete(&(proc->links));
    waitLock->waitProcs.size--;

    /* Undo increments of request counts by waiting process */
    Assert(waitLock->nRequested > 0);
    Assert(waitLock->nRequested > proc->waitLock->nGranted);
    waitLock->nRequested--;
    Assert(waitLock->requested[lockmode] > 0);
    waitLock->requested[lockmode]--;
    /* don't forget to clear waitMask bit if appropriate */
    if (waitLock->granted[lockmode] == waitLock->requested[lockmode])
        waitLock->waitMask &= LOCKBIT_OFF(lockmode);

    /* Clean up the proc's own state, and pass it the ok/fail signal */
    proc->waitLock = NULL;
    proc->waitProcLock = NULL;
    proc->waitStatus = STATUS_ERROR;

    /*
     * Delete the proclock immediately if it represents no already-held locks.
     * (This must happen now because if the owner of the lock decides to
     * release it, and the requested/granted counts then go to zero,
     * LockRelease expects there to be no remaining proclocks.) Then see if
     * any other waiters for the lock can be woken up now.
     */
    CleanUpLock(waitLock, proclock,
                LockMethods[lockmethodid], hashcode,
                true);
}

static void RemoveLocalLock ( LOCALLOCK locallock  )  [static]
static PROCLOCK * SetupLockInTable ( LockMethod  lockMethodTable,
PGPROC proc,
const LOCKTAG locktag,
uint32  hashcode,
LOCKMODE  lockmode 
) [static]

Definition at line 1041 of file lock.c.

References Assert, elog, ERROR, LOCK::granted, LOCK::grantMask, HASH_REMOVE, hash_search_with_hash_value(), PROCLOCK::holdMask, i, LOCK_PRINT, LOCKBIT_ON, LockHashPartition, PROCLOCK::lockLink, LockMethodData::lockModeNames, LOCKTAG::locktag_field1, LOCKTAG::locktag_field2, LOCKTAG::locktag_field3, LOG, MAX_LOCKMODES, MemSet, PROCLOCKTAG::myLock, PROCLOCKTAG::myProc, PGPROC::myProcLocks, LOCK::nGranted, LOCK::nRequested, NULL, LockMethodData::numLockModes, PANIC, PROCLOCK::procLink, PROCLOCK_PRINT, ProcLockHashCode(), LOCK::procLocks, ProcQueueInit(), PROCLOCK::releaseMask, LOCK::requested, SHMQueueEmpty(), SHMQueueInit(), SHMQueueInsertBefore(), LOCK::tag, LOCK::waitMask, and LOCK::waitProcs.

Referenced by FastPathGetRelationLockEntry(), FastPathTransferRelationLocks(), LockAcquireExtended(), and VirtualXactLock().

{
    LOCK       *lock;
    PROCLOCK   *proclock;
    PROCLOCKTAG proclocktag;
    uint32      proclock_hashcode;
    bool        found;

    /*
     * Find or create a lock with this tag.
     *
     * Note: if the locallock object already existed, it might have a pointer
     * to the lock already ... but we probably should not assume that that
     * pointer is valid, since a lock object with no locks can go away
     * anytime.
     */
    lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
                                                (const void *) locktag,
                                                hashcode,
                                                HASH_ENTER_NULL,
                                                &found);
    if (!lock)
        return NULL;

    /*
     * if it's a new lock object, initialize it
     */
    if (!found)
    {
        lock->grantMask = 0;
        lock->waitMask = 0;
        SHMQueueInit(&(lock->procLocks));
        ProcQueueInit(&(lock->waitProcs));
        lock->nRequested = 0;
        lock->nGranted = 0;
        MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);
        MemSet(lock->granted, 0, sizeof(int) * MAX_LOCKMODES);
        LOCK_PRINT("LockAcquire: new", lock, lockmode);
    }
    else
    {
        LOCK_PRINT("LockAcquire: found", lock, lockmode);
        Assert((lock->nRequested >= 0) && (lock->requested[lockmode] >= 0));
        Assert((lock->nGranted >= 0) && (lock->granted[lockmode] >= 0));
        Assert(lock->nGranted <= lock->nRequested);
    }

    /*
     * Create the hash key for the proclock table.
     */
    proclocktag.myLock = lock;
    proclocktag.myProc = proc;

    proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);

    /*
     * Find or create a proclock entry with this tag
     */
    proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,
                                                        (void *) &proclocktag,
                                                        proclock_hashcode,
                                                        HASH_ENTER_NULL,
                                                        &found);
    if (!proclock)
    {
        /* Ooops, not enough shmem for the proclock */
        if (lock->nRequested == 0)
        {
            /*
             * There are no other requestors of this lock, so garbage-collect
             * the lock object.  We *must* do this to avoid a permanent leak
             * of shared memory, because there won't be anything to cause
             * anyone to release the lock object later.
             */
            Assert(SHMQueueEmpty(&(lock->procLocks)));
            if (!hash_search_with_hash_value(LockMethodLockHash,
                                             (void *) &(lock->tag),
                                             hashcode,
                                             HASH_REMOVE,
                                             NULL))
                elog(PANIC, "lock table corrupted");
        }
        return NULL;
    }

    /*
     * If new, initialize the new entry
     */
    if (!found)
    {
        uint32      partition = LockHashPartition(hashcode);

        proclock->holdMask = 0;
        proclock->releaseMask = 0;
        /* Add proclock to appropriate lists */
        SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);
        SHMQueueInsertBefore(&(proc->myProcLocks[partition]),
                             &proclock->procLink);
        PROCLOCK_PRINT("LockAcquire: new", proclock);
    }
    else
    {
        PROCLOCK_PRINT("LockAcquire: found", proclock);
        Assert((proclock->holdMask & ~lock->grantMask) == 0);

#ifdef CHECK_DEADLOCK_RISK

        /*
         * Issue warning if we already hold a lower-level lock on this object
         * and do not hold a lock of the requested level or higher. This
         * indicates a deadlock-prone coding practice (eg, we'd have a
         * deadlock if another backend were following the same code path at
         * about the same time).
         *
         * This is not enabled by default, because it may generate log entries
         * about user-level coding practices that are in fact safe in context.
         * It can be enabled to help find system-level problems.
         *
         * XXX Doing numeric comparison on the lockmodes is a hack; it'd be
         * better to use a table.  For now, though, this works.
         */
        {
            int         i;

            for (i = lockMethodTable->numLockModes; i > 0; i--)
            {
                if (proclock->holdMask & LOCKBIT_ON(i))
                {
                    if (i >= (int) lockmode)
                        break;  /* safe: we have a lock >= req level */
                    elog(LOG, "deadlock risk: raising lock level"
                         " from %s to %s on object %u/%u/%u",
                         lockMethodTable->lockModeNames[i],
                         lockMethodTable->lockModeNames[lockmode],
                         lock->tag.locktag_field1, lock->tag.locktag_field2,
                         lock->tag.locktag_field3);
                    break;
                }
            }
        }
#endif   /* CHECK_DEADLOCK_RISK */
    }

    /*
     * lock->nRequested and lock->requested[] count the total number of
     * requests, whether granted or waiting, so increment those immediately.
     * The other counts don't increment till we get the lock.
     */
    lock->nRequested++;
    lock->requested[lockmode]++;
    Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));

    /*
     * We shouldn't already hold the desired lock; else locallock table is
     * broken.
     */
    if (proclock->holdMask & LOCKBIT_ON(lockmode))
        elog(ERROR, "lock %s on object %u/%u/%u is already held",
             lockMethodTable->lockModeNames[lockmode],
             lock->tag.locktag_field1, lock->tag.locktag_field2,
             lock->tag.locktag_field3);

    return proclock;
}

static bool UnGrantLock ( LOCK lock,
LOCKMODE  lockmode,
PROCLOCK proclock,
LockMethod  lockMethodTable 
) [static]

Definition at line 1348 of file lock.c.

References Assert, LockMethodData::conflictTab, LOCK::granted, LOCK::grantMask, PROCLOCK::holdMask, LOCK_PRINT, LOCKBIT_OFF, LOCK::nGranted, LOCK::nRequested, PROCLOCK_PRINT, LOCK::requested, and LOCK::waitMask.

Referenced by LockRefindAndRelease(), LockRelease(), and LockReleaseAll().

{
    bool        wakeupNeeded = false;

    Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
    Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
    Assert(lock->nGranted <= lock->nRequested);

    /*
     * fix the general lock stats
     */
    lock->nRequested--;
    lock->requested[lockmode]--;
    lock->nGranted--;
    lock->granted[lockmode]--;

    if (lock->granted[lockmode] == 0)
    {
        /* change the conflict mask.  No more of this lock type. */
        lock->grantMask &= LOCKBIT_OFF(lockmode);
    }

    LOCK_PRINT("UnGrantLock: updated", lock, lockmode);

    /*
     * We need only run ProcLockWakeup if the released lock conflicts with at
     * least one of the lock types requested by waiter(s).  Otherwise whatever
     * conflict made them wait must still exist.  NOTE: before MVCC, we could
     * skip wakeup if lock->granted[lockmode] was still positive. But that's
     * not true anymore, because the remaining granted locks might belong to
     * some waiter, who could now be awakened because he doesn't conflict with
     * his own locks.
     */
    if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
        wakeupNeeded = true;

    /*
     * Now fix the per-proclock state.
     */
    proclock->holdMask &= LOCKBIT_OFF(lockmode);
    PROCLOCK_PRINT("UnGrantLock: updated", proclock);

    return wakeupNeeded;
}

bool VirtualXactLock ( VirtualTransactionId  vxid,
bool  wait 
)

Definition at line 3930 of file lock.c.

References Assert, PGPROC::backendId, VirtualTransactionId::backendId, BackendIdGetProc(), PGPROC::backendLock, DEFAULT_LOCKMETHOD, ereport, errcode(), errhint(), errmsg(), ERROR, ExclusiveLock, PGPROC::fpLocalTransactionId, PGPROC::fpVXIDLock, GrantLock(), VirtualTransactionId::localTransactionId, LockAcquire(), LockHashPartitionLock, LockRelease(), LockTagHashCode(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PROCLOCKTAG::myLock, NULL, SET_LOCKTAG_VIRTUALTRANSACTION, SetupLockInTable(), ShareLock, PROCLOCK::tag, and VirtualTransactionIdIsValid.

Referenced by DefineIndex(), index_drop(), and ResolveRecoveryConflictWithVirtualXIDs().

{
    LOCKTAG     tag;
    PGPROC     *proc;

    Assert(VirtualTransactionIdIsValid(vxid));

    SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid);

    /*
     * If a lock table entry must be made, this is the PGPROC on whose behalf
     * it must be done.  Note that the transaction might end or the PGPROC
     * might be reassigned to a new backend before we get around to examining
     * it, but it doesn't matter.  If we find upon examination that the
     * relevant lxid is no longer running here, that's enough to prove that
     * it's no longer running anywhere.
     */
    proc = BackendIdGetProc(vxid.backendId);
    if (proc == NULL)
        return true;

    /*
     * We must acquire this lock before checking the backendId and lxid
     * against the ones we're waiting for.  The target backend will only set
     * or clear lxid while holding this lock.
     */
    LWLockAcquire(proc->backendLock, LW_EXCLUSIVE);

    /* If the transaction has ended, our work here is done. */
    if (proc->backendId != vxid.backendId
        || proc->fpLocalTransactionId != vxid.localTransactionId)
    {
        LWLockRelease(proc->backendLock);
        return true;
    }

    /*
     * If we aren't asked to wait, there's no need to set up a lock table
     * entry.  The transaction is still in progress, so just return false.
     */
    if (!wait)
    {
        LWLockRelease(proc->backendLock);
        return false;
    }

    /*
     * OK, we're going to need to sleep on the VXID.  But first, we must set
     * up the primary lock table entry, if needed (ie, convert the proc's
     * fast-path lock on its VXID to a regular lock).
     */
    if (proc->fpVXIDLock)
    {
        PROCLOCK   *proclock;
        uint32      hashcode;
        LWLockId    partitionLock;

        hashcode = LockTagHashCode(&tag);

        partitionLock = LockHashPartitionLock(hashcode);
        LWLockAcquire(partitionLock, LW_EXCLUSIVE);

        proclock = SetupLockInTable(LockMethods[DEFAULT_LOCKMETHOD], proc,
                                    &tag, hashcode, ExclusiveLock);
        if (!proclock)
        {
            LWLockRelease(partitionLock);
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of shared memory"),
                     errhint("You might need to increase max_locks_per_transaction.")));
        }
        GrantLock(proclock->tag.myLock, proclock, ExclusiveLock);

        LWLockRelease(partitionLock);

        proc->fpVXIDLock = false;
    }

    /* Done with proc->fpLockBits */
    LWLockRelease(proc->backendLock);

    /* Time to wait. */
    (void) LockAcquire(&tag, ShareLock, false, false);

    LockRelease(&tag, ShareLock, false);
    return true;
}

void VirtualXactLockTableCleanup ( void   ) 
void VirtualXactLockTableInsert ( VirtualTransactionId  vxid  ) 
static void WaitOnLock ( LOCALLOCK locallock,
ResourceOwner  owner 
) [static]

Definition at line 1566 of file lock.c.

References DeadLockReport(), get_ps_display(), LOCALLOCK::hashcode, LOCALLOCK_LOCKMETHOD, LOCALLOCK::lock, LOCK_PRINT, LockHashPartitionLock, LWLockRelease(), LOCALLOCKTAG::mode, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pgstat_report_waiting(), ProcSleep(), set_ps_display(), STATUS_OK, LOCALLOCK::tag, and update_process_title.

Referenced by LockAcquireExtended().

{
    LOCKMETHODID lockmethodid = LOCALLOCK_LOCKMETHOD(*locallock);
    LockMethod  lockMethodTable = LockMethods[lockmethodid];
    char       *volatile new_status = NULL;

    LOCK_PRINT("WaitOnLock: sleeping on lock",
               locallock->lock, locallock->tag.mode);

    /* Report change to waiting status */
    if (update_process_title)
    {
        const char *old_status;
        int         len;

        old_status = get_ps_display(&len);
        new_status = (char *) palloc(len + 8 + 1);
        memcpy(new_status, old_status, len);
        strcpy(new_status + len, " waiting");
        set_ps_display(new_status, false);
        new_status[len] = '\0'; /* truncate off " waiting" */
    }
    pgstat_report_waiting(true);

    awaitedLock = locallock;
    awaitedOwner = owner;

    /*
     * NOTE: Think not to put any shared-state cleanup after the call to
     * ProcSleep, in either the normal or failure path.  The lock state must
     * be fully set by the lock grantor, or by CheckDeadLock if we give up
     * waiting for the lock.  This is necessary because of the possibility
     * that a cancel/die interrupt will interrupt ProcSleep after someone else
     * grants us the lock, but before we've noticed it. Hence, after granting,
     * the locktable state must fully reflect the fact that we own the lock;
     * we can't do additional work on return.
     *
     * We can and do use a PG_TRY block to try to clean up after failure, but
     * this still has a major limitation: elog(FATAL) can occur while waiting
     * (eg, a "die" interrupt), and then control won't come back here. So all
     * cleanup of essential state should happen in LockErrorCleanup, not here.
     * We can use PG_TRY to clear the "waiting" status flags, since doing that
     * is unimportant if the process exits.
     */
    PG_TRY();
    {
        if (ProcSleep(locallock, lockMethodTable) != STATUS_OK)
        {
            /*
             * We failed as a result of a deadlock, see CheckDeadLock(). Quit
             * now.
             */
            awaitedLock = NULL;
            LOCK_PRINT("WaitOnLock: aborting on lock",
                       locallock->lock, locallock->tag.mode);
            LWLockRelease(LockHashPartitionLock(locallock->hashcode));

            /*
             * Now that we aren't holding the partition lock, we can give an
             * error report including details about the detected deadlock.
             */
            DeadLockReport();
            /* not reached */
        }
    }
    PG_CATCH();
    {
        /* In this path, awaitedLock remains set until LockErrorCleanup */

        /* Report change to non-waiting status */
        pgstat_report_waiting(false);
        if (update_process_title)
        {
            set_ps_display(new_status, false);
            pfree(new_status);
        }

        /* and propagate the error */
        PG_RE_THROW();
    }
    PG_END_TRY();

    awaitedLock = NULL;

    /* Report change to non-waiting status */
    pgstat_report_waiting(false);
    if (update_process_title)
    {
        set_ps_display(new_status, false);
        pfree(new_status);
    }

    LOCK_PRINT("WaitOnLock: wakeup on lock",
               locallock->lock, locallock->tag.mode);
}


Variable Documentation

Definition at line 257 of file lock.c.

Definition at line 258 of file lock.c.

Initial value:
 {
    AccessExclusiveLock,        
    LockConflicts,
    lock_mode_names,



    &Dummy_trace

}

Definition at line 122 of file lock.c.

bool Dummy_trace = false [static]

Definition at line 119 of file lock.c.

int FastPathLocalUseCount = 0 [static]

Definition at line 241 of file lock.c.

const char* const lock_mode_names[] [static]
Initial value:
{
    "INVALID",
    "AccessShareLock",
    "RowShareLock",
    "RowExclusiveLock",
    "ShareUpdateExclusiveLock",
    "ShareLock",
    "ShareRowExclusiveLock",
    "ExclusiveLock",
    "AccessExclusiveLock"
}

Definition at line 105 of file lock.c.

const LOCKMASK LockConflicts[] [static]

Definition at line 62 of file lock.c.

Definition at line 252 of file lock.c.

Definition at line 250 of file lock.c.

Definition at line 251 of file lock.c.

const LockMethod LockMethods[] [static]
Initial value:

Definition at line 147 of file lock.c.

Definition at line 51 of file lock.c.

Referenced by BootStrapXLOG(), CheckRequiredParameterValues(), and XLogReportParameters().

Definition at line 256 of file lock.c.

Initial value:
 {
    AccessExclusiveLock,        
    LockConflicts,
    lock_mode_names,



    &Dummy_trace

}

Definition at line 133 of file lock.c.