*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.79 2005/10/15 02:49:26 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.80 2005/12/09 01:22:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/subtrans.h"
#include "access/transam.h"
#include "access/xact.h"
-#include "catalog/catalog.h"
#include "miscadmin.h"
#include "storage/lmgr.h"
#include "storage/procarray.h"
#include "utils/inval.h"
-/*
- * This conflict table defines the semantics of the various lock modes.
- */
-static const LOCKMASK LockConflicts[] = {
- 0,
-
- /* AccessShareLock */
- (1 << AccessExclusiveLock),
-
- /* RowShareLock */
- (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
-
- /* RowExclusiveLock */
- (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
- (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
-
- /* ShareUpdateExclusiveLock */
- (1 << ShareUpdateExclusiveLock) |
- (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
- (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
-
- /* ShareLock */
- (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
- (1 << ShareRowExclusiveLock) |
- (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
-
- /* ShareRowExclusiveLock */
- (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
- (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
- (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
-
- /* ExclusiveLock */
- (1 << RowShareLock) |
- (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
- (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
- (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
-
- /* AccessExclusiveLock */
- (1 << AccessShareLock) | (1 << RowShareLock) |
- (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
- (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
- (1 << ExclusiveLock) | (1 << AccessExclusiveLock)
-
-};
-
-static LOCKMETHODID LockTableId = INVALID_LOCKMETHOD;
-
-
-/*
- * Create the lock table described by LockConflicts
- */
-void
-InitLockTable(void)
-{
- LOCKMETHODID LongTermTableId;
-
- /* there's no zero-th table */
- NumLockMethods = 1;
-
- /*
- * Create the default lock method table
- */
-
- /* number of lock modes is lengthof()-1 because of dummy zero */
- LockTableId = LockMethodTableInit("LockTable",
- LockConflicts,
- lengthof(LockConflicts) - 1);
- if (!LockMethodIsValid(LockTableId))
- elog(ERROR, "could not initialize lock table");
- Assert(LockTableId == DEFAULT_LOCKMETHOD);
-
-#ifdef USER_LOCKS
-
- /*
- * Allocate another tableId for user locks (same shared hashtable though)
- */
- LongTermTableId = LockMethodTableRename(LockTableId);
- if (!LockMethodIsValid(LongTermTableId))
- elog(ERROR, "could not rename user lock table");
- Assert(LongTermTableId == USER_LOCKMETHOD);
-#endif
-}
-
/*
* RelationInitLockInfo
* Initializes the lock information in a relation descriptor.
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
- res = LockAcquire(LockTableId, &tag, relation->rd_istemp,
- lockmode, false, false);
+ res = LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
/*
* Check to see if the relcache entry has been invalidated while we were
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
- res = LockAcquire(LockTableId, &tag, relation->rd_istemp,
- lockmode, false, true);
+ res = LockAcquire(&tag, relation->rd_istemp, lockmode, false, true);
if (res == LOCKACQUIRE_NOT_AVAIL)
return false;
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
- LockRelease(LockTableId, &tag, lockmode, false);
+ LockRelease(&tag, lockmode, false);
}
/*
SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
- (void) LockAcquire(LockTableId, &tag, istemprel,
- lockmode, true, false);
+ (void) LockAcquire(&tag, istemprel, lockmode, true, false);
}
/*
SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
- LockRelease(LockTableId, &tag, lockmode, true);
+ LockRelease(&tag, lockmode, true);
}
/*
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
- (void) LockAcquire(LockTableId, &tag, relation->rd_istemp,
- lockmode, false, false);
+ (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
}
/*
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
- LockRelease(LockTableId, &tag, lockmode, false);
+ LockRelease(&tag, lockmode, false);
}
/*
relation->rd_lockInfo.lockRelId.relId,
blkno);
- (void) LockAcquire(LockTableId, &tag, relation->rd_istemp,
- lockmode, false, false);
+ (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
}
/*
relation->rd_lockInfo.lockRelId.relId,
blkno);
- return (LockAcquire(LockTableId, &tag, relation->rd_istemp,
+ return (LockAcquire(&tag, relation->rd_istemp,
lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
}
relation->rd_lockInfo.lockRelId.relId,
blkno);
- LockRelease(LockTableId, &tag, lockmode, false);
+ LockRelease(&tag, lockmode, false);
}
/*
ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid));
- (void) LockAcquire(LockTableId, &tag, relation->rd_istemp,
- lockmode, false, false);
+ (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
}
/*
ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid));
- return (LockAcquire(LockTableId, &tag, relation->rd_istemp,
+ return (LockAcquire(&tag, relation->rd_istemp,
lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
}
ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid));
- LockRelease(LockTableId, &tag, lockmode, false);
+ LockRelease(&tag, lockmode, false);
}
/*
SET_LOCKTAG_TRANSACTION(tag, xid);
- (void) LockAcquire(LockTableId, &tag, false,
- ExclusiveLock, false, false);
+ (void) LockAcquire(&tag, false, ExclusiveLock, false, false);
}
/*
SET_LOCKTAG_TRANSACTION(tag, xid);
- LockRelease(LockTableId, &tag, ExclusiveLock, false);
+ LockRelease(&tag, ExclusiveLock, false);
}
/*
SET_LOCKTAG_TRANSACTION(tag, xid);
- (void) LockAcquire(LockTableId, &tag, false,
- ShareLock, false, false);
+ (void) LockAcquire(&tag, false, ShareLock, false, false);
- LockRelease(LockTableId, &tag, ShareLock, false);
+ LockRelease(&tag, ShareLock, false);
if (!TransactionIdIsInProgress(xid))
break;
SET_LOCKTAG_TRANSACTION(tag, xid);
- if (LockAcquire(LockTableId, &tag, false,
+ if (LockAcquire(&tag, false,
ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
return false;
- LockRelease(LockTableId, &tag, ShareLock, false);
+ LockRelease(&tag, ShareLock, false);
if (!TransactionIdIsInProgress(xid))
break;
objid,
objsubid);
- (void) LockAcquire(LockTableId, &tag, false,
- lockmode, false, false);
+ (void) LockAcquire(&tag, false, lockmode, false, false);
}
/*
objid,
objsubid);
- LockRelease(LockTableId, &tag, lockmode, false);
+ LockRelease(&tag, lockmode, false);
}
/*
objid,
objsubid);
- (void) LockAcquire(LockTableId, &tag, false,
- lockmode, false, false);
+ (void) LockAcquire(&tag, false, lockmode, false, false);
}
/*
objid,
objsubid);
- LockRelease(LockTableId, &tag, lockmode, false);
+ LockRelease(&tag, lockmode, false);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.160 2005/11/22 18:17:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.161 2005/12/09 01:22:04 tgl Exp $
*
* NOTES
- * Outside modules can create a lock table and acquire/release
- * locks. A lock table is a shared memory hash table. When
+ * A lock table is a shared memory hash table. When
* a process tries to acquire a lock of a type that conflicts
* with existing locks, it is put to sleep using the routines
* in storage/lmgr/proc.c.
*
* Interface:
*
- * LockAcquire(), LockRelease(), LockMethodTableInit(),
- * LockMethodTableRename(), LockReleaseAll(),
+ * InitLocks(), GetLocksMethodTable(),
+ * LockAcquire(), LockRelease(), LockReleaseAll(),
* LockCheckConflicts(), GrantLock()
*
*-------------------------------------------------------------------------
mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
-/* Record that's written to 2PC state file when a lock is persisted */
-typedef struct TwoPhaseLockRecord
-{
- LOCKTAG locktag;
- LOCKMODE lockmode;
-} TwoPhaseLockRecord;
-
-
/*
- * map from lock method id to the lock table data structures
+ * Data structures defining the semantics of the standard lock methods.
+ *
+ * The conflict table defines the semantics of the various lock modes.
*/
-static LockMethod LockMethods[MAX_LOCK_METHODS];
-static HTAB *LockMethodLockHash[MAX_LOCK_METHODS];
-static HTAB *LockMethodProcLockHash[MAX_LOCK_METHODS];
-static HTAB *LockMethodLocalHash[MAX_LOCK_METHODS];
-
-/* exported so lmgr.c can initialize it */
-int NumLockMethods;
-
-
-/* private state for GrantAwaitedLock */
-static LOCALLOCK *awaitedLock;
-static ResourceOwner awaitedOwner;
+static const LOCKMASK LockConflicts[] = {
+ 0,
+
+ /* AccessShareLock */
+ (1 << AccessExclusiveLock),
+
+ /* RowShareLock */
+ (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+ /* RowExclusiveLock */
+ (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
+ (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+ /* ShareUpdateExclusiveLock */
+ (1 << ShareUpdateExclusiveLock) |
+ (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
+ (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+ /* ShareLock */
+ (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
+ (1 << ShareRowExclusiveLock) |
+ (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+ /* ShareRowExclusiveLock */
+ (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
+ (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
+ (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+ /* ExclusiveLock */
+ (1 << RowShareLock) |
+ (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
+ (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
+ (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+ /* AccessExclusiveLock */
+ (1 << AccessShareLock) | (1 << RowShareLock) |
+ (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
+ (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
+ (1 << ExclusiveLock) | (1 << AccessExclusiveLock)
+};
+/* Names of lock modes, for debug printouts */
static const char *const lock_mode_names[] =
{
"INVALID",
"AccessExclusiveLock"
};
+#ifndef LOCK_DEBUG
+static bool Dummy_trace = false;
+#endif
+
+static const LockMethodData default_lockmethod = {
+ AccessExclusiveLock, /* highest valid lock mode number */
+ true,
+ LockConflicts,
+ lock_mode_names,
+#ifdef LOCK_DEBUG
+ &Trace_locks
+#else
+ &Dummy_trace
+#endif
+};
+
+#ifdef USER_LOCKS
+
+static const LockMethodData user_lockmethod = {
+ AccessExclusiveLock, /* highest valid lock mode number */
+ false,
+ LockConflicts,
+ lock_mode_names,
+#ifdef LOCK_DEBUG
+ &Trace_userlocks
+#else
+ &Dummy_trace
+#endif
+};
+
+#endif /* USER_LOCKS */
+
+/*
+ * map from lock method id to the lock table data structures
+ */
+static const LockMethod LockMethods[] = {
+ NULL,
+ &default_lockmethod,
+#ifdef USER_LOCKS
+ &user_lockmethod
+#endif
+};
+
+
+/* Record that's written to 2PC state file when a lock is persisted */
+typedef struct TwoPhaseLockRecord
+{
+ LOCKTAG locktag;
+ LOCKMODE lockmode;
+} TwoPhaseLockRecord;
+
+
+/*
+ * Links to hash tables containing lock state
+ */
+static HTAB *LockMethodLockHash;
+static HTAB *LockMethodProcLockHash;
+static HTAB *LockMethodLocalHash;
+
+
+/* private state for GrantAwaitedLock */
+static LOCALLOCK *awaitedLock;
+static ResourceOwner awaitedOwner;
+
#ifdef LOCK_DEBUG
inline static bool
-LOCK_DEBUG_ENABLED(const LOCK *lock)
+LOCK_DEBUG_ENABLED(const LOCKTAG *tag)
{
return
- (((Trace_locks && LOCK_LOCKMETHOD(*lock) == DEFAULT_LOCKMETHOD)
- || (Trace_userlocks && LOCK_LOCKMETHOD(*lock) == USER_LOCKMETHOD))
- && ((Oid) lock->tag.locktag_field2 >= (Oid) Trace_lock_oidmin))
- || (Trace_lock_table
- && (lock->tag.locktag_field2 == Trace_lock_table));
+ (*(LockMethods[tag->locktag_lockmethodid]->trace_flag) &&
+ ((Oid) tag->locktag_field2 >= (Oid) Trace_lock_oidmin))
+ || (Trace_lock_table &&
+ (tag->locktag_field2 == Trace_lock_table));
}
inline static void
LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
{
- if (LOCK_DEBUG_ENABLED(lock))
+ if (LOCK_DEBUG_ENABLED(&lock->tag))
elog(LOG,
"%s: lock(%lx) id(%u,%u,%u,%u,%u,%u) grantMask(%x) "
"req(%d,%d,%d,%d,%d,%d,%d)=%d "
lock->granted[1], lock->granted[2], lock->granted[3],
lock->granted[4], lock->granted[5], lock->granted[6],
lock->granted[7], lock->nGranted,
- lock->waitProcs.size, lock_mode_names[type]);
+ lock->waitProcs.size,
+ LockMethods[LOCK_LOCKMETHOD(*lock)]->lockModeNames[type]);
}
inline static void
PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
{
- if (LOCK_DEBUG_ENABLED((LOCK *) MAKE_PTR(proclockP->tag.lock)))
+ if (LOCK_DEBUG_ENABLED(&((LOCK *) MAKE_PTR(proclockP->tag.lock))->tag))
elog(LOG,
"%s: proclock(%lx) lock(%lx) method(%u) proc(%lx) hold(%x)",
where, MAKE_OFFSET(proclockP), proclockP->tag.lock,
/*
- * InitLocks -- Init the lock module. Nothing to do here at present.
+ * InitLocks -- Initialize the lock module's shared memory.
*/
void
InitLocks(void)
{
- /* NOP */
-}
-
-
-/*
- * Fetch the lock method table associated with a given lock
- */
-LockMethod
-GetLocksMethodTable(LOCK *lock)
-{
- LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*lock);
-
- Assert(0 < lockmethodid && lockmethodid < NumLockMethods);
- return LockMethods[lockmethodid];
-}
-
-
-/*
- * LockMethodInit -- initialize the lock table's lock type
- * structures
- *
- * Notes: just copying. Should only be called once.
- */
-static void
-LockMethodInit(LockMethod lockMethodTable,
- const LOCKMASK *conflictsP,
- int numModes)
-{
- int i;
-
- lockMethodTable->numLockModes = numModes;
- /* copies useless zero element as well as the N lockmodes */
- for (i = 0; i <= numModes; i++)
- lockMethodTable->conflictTab[i] = conflictsP[i];
-}
-
-/*
- * LockMethodTableInit -- initialize a lock table structure
- *
- * NOTE: data structures allocated here are allocated permanently, using
- * TopMemoryContext and shared memory. We don't ever release them anyway,
- * and in normal multi-backend operation the lock table structures set up
- * by the postmaster are inherited by each backend, so they must be in
- * TopMemoryContext.
- */
-LOCKMETHODID
-LockMethodTableInit(const char *tabName,
- const LOCKMASK *conflictsP,
- int numModes)
-{
- LockMethod newLockMethod;
- LOCKMETHODID lockmethodid;
- char *shmemName;
+ char shmemName[64];
HASHCTL info;
int hash_flags;
- bool found;
long init_table_size,
max_table_size;
- if (numModes >= MAX_LOCKMODES)
- elog(ERROR, "too many lock types %d (limit is %d)",
- numModes, MAX_LOCKMODES - 1);
-
/* Compute init/max size to request for lock hashtables */
max_table_size = NLOCKENTS();
init_table_size = max_table_size / 2;
- /* Allocate a string for the shmem index table lookups. */
- /* This is just temp space in this routine, so palloc is OK. */
- shmemName = (char *) palloc(strlen(tabName) + 32);
-
- /* each lock table has a header in shared memory */
- sprintf(shmemName, "%s (lock method table)", tabName);
- newLockMethod = (LockMethod)
- ShmemInitStruct(shmemName, sizeof(LockMethodData), &found);
-
- if (!newLockMethod)
- elog(FATAL, "could not initialize lock table \"%s\"", tabName);
-
- /*
- * we're first - initialize
- */
- if (!found)
- {
- MemSet(newLockMethod, 0, sizeof(LockMethodData));
- newLockMethod->masterLock = LockMgrLock;
- LockMethodInit(newLockMethod, conflictsP, numModes);
- }
-
- /*
- * other modules refer to the lock table by a lockmethod ID
- */
- Assert(NumLockMethods < MAX_LOCK_METHODS);
- lockmethodid = NumLockMethods++;
- LockMethods[lockmethodid] = newLockMethod;
-
/*
* allocate a hash table for LOCK structs. This is used to store
* per-locked-object information.
info.hash = tag_hash;
hash_flags = (HASH_ELEM | HASH_FUNCTION);
- sprintf(shmemName, "%s (lock hash)", tabName);
- LockMethodLockHash[lockmethodid] = ShmemInitHash(shmemName,
- init_table_size,
- max_table_size,
- &info,
- hash_flags);
+ sprintf(shmemName, "LOCK hash");
+ LockMethodLockHash = ShmemInitHash(shmemName,
+ init_table_size,
+ max_table_size,
+ &info,
+ hash_flags);
- if (!LockMethodLockHash[lockmethodid])
- elog(FATAL, "could not initialize lock table \"%s\"", tabName);
+ if (!LockMethodLockHash)
+ elog(FATAL, "could not initialize lock table \"%s\"", shmemName);
/*
* allocate a hash table for PROCLOCK structs. This is used to store
info.hash = tag_hash;
hash_flags = (HASH_ELEM | HASH_FUNCTION);
- sprintf(shmemName, "%s (proclock hash)", tabName);
- LockMethodProcLockHash[lockmethodid] = ShmemInitHash(shmemName,
- init_table_size,
- max_table_size,
- &info,
- hash_flags);
+ sprintf(shmemName, "PROCLOCK hash");
+ LockMethodProcLockHash = ShmemInitHash(shmemName,
+ init_table_size,
+ max_table_size,
+ &info,
+ hash_flags);
- if (!LockMethodProcLockHash[lockmethodid])
- elog(FATAL, "could not initialize lock table \"%s\"", tabName);
+ if (!LockMethodProcLockHash)
+ elog(FATAL, "could not initialize lock table \"%s\"", shmemName);
/*
* allocate a non-shared hash table for LOCALLOCK structs. This is used
* 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[lockmethodid])
- hash_destroy(LockMethodLocalHash[lockmethodid]);
+ if (LockMethodLocalHash)
+ hash_destroy(LockMethodLocalHash);
info.keysize = sizeof(LOCALLOCKTAG);
info.entrysize = sizeof(LOCALLOCK);
info.hash = tag_hash;
hash_flags = (HASH_ELEM | HASH_FUNCTION);
- sprintf(shmemName, "%s (locallock hash)", tabName);
- LockMethodLocalHash[lockmethodid] = hash_create(shmemName,
- 128,
- &info,
- hash_flags);
-
- pfree(shmemName);
-
- return lockmethodid;
+ LockMethodLocalHash = hash_create("LOCALLOCK hash",
+ 128,
+ &info,
+ hash_flags);
}
+
/*
- * LockMethodTableRename -- allocate another lockmethod ID to the same
- * lock table.
- *
- * NOTES: This function makes it possible to have different lockmethodids,
- * and hence different locking semantics, while still storing all
- * the data in one shared-memory hashtable.
+ * Fetch the lock method table associated with a given lock
*/
-
-LOCKMETHODID
-LockMethodTableRename(LOCKMETHODID lockmethodid)
+LockMethod
+GetLocksMethodTable(const LOCK *lock)
{
- LOCKMETHODID newLockMethodId;
-
- if (NumLockMethods >= MAX_LOCK_METHODS)
- return INVALID_LOCKMETHOD;
- if (LockMethods[lockmethodid] == INVALID_LOCKMETHOD)
- return INVALID_LOCKMETHOD;
-
- /* other modules refer to the lock table by a lockmethod ID */
- newLockMethodId = NumLockMethods;
- NumLockMethods++;
-
- LockMethods[newLockMethodId] = LockMethods[lockmethodid];
- LockMethodLockHash[newLockMethodId] = LockMethodLockHash[lockmethodid];
- LockMethodProcLockHash[newLockMethodId] = LockMethodProcLockHash[lockmethodid];
- LockMethodLocalHash[newLockMethodId] = LockMethodLocalHash[lockmethodid];
+ LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*lock);
- return newLockMethodId;
+ Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
+ return LockMethods[lockmethodid];
}
+
/*
* LockAcquire -- Check for lock conflicts, sleep if conflict found,
* set lock if/when no conflicts.
*
* Inputs:
- * lockmethodid: identifies which lock table to use
* locktag: unique identifier for the lockable object
* isTempObject: is the lockable object a temporary object? (Under 2PC,
* such locks cannot be persisted)
*
* NOTE: if we wait for the lock, there is no way to abort the wait
* short of aborting the transaction.
- *
- *
- * Note on User Locks:
- *
- * User locks are handled totally on the application side as
- * long term cooperative locks which extend beyond the normal
- * transaction boundaries. Their purpose is to indicate to an
- * application that someone is `working' on an item. So it is
- * possible to put an user lock on a tuple's oid, retrieve the
- * tuple, work on it for an hour and then update it and remove
- * the lock. While the lock is active other clients can still
- * read and write the tuple but they can be aware that it has
- * been locked at the application level by someone.
- *
- * User locks and normal locks are completely orthogonal and
- * they don't interfere with each other.
- *
- * User locks are always non blocking, therefore they are never
- * acquired if already held by another process. They must be
- * released explicitly by the application but they are released
- * automatically when a backend terminates.
- * They are indicated by a lockmethod 2 which is an alias for the
- * normal lock table.
- *
- * The lockmode parameter can have the same values for normal locks
- * although probably only WRITE_LOCK can have some practical use.
- *
- * DZ - 22 Nov 1997
*/
LockAcquireResult
-LockAcquire(LOCKMETHODID lockmethodid,
- LOCKTAG *locktag,
+LockAcquire(const LOCKTAG *locktag,
bool isTempObject,
LOCKMODE lockmode,
bool sessionLock,
bool dontWait)
{
+ LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
+ LockMethod lockMethodTable;
LOCALLOCKTAG localtag;
LOCALLOCK *locallock;
LOCK *lock;
bool found;
ResourceOwner owner;
LWLockId masterLock;
- LockMethod lockMethodTable;
int status;
+ 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 (Trace_userlocks && lockmethodid == USER_LOCKMETHOD)
- elog(LOG, "LockAcquire: user lock [%u,%u] %s",
+ if (LOCK_DEBUG_ENABLED(locktag))
+ elog(LOG, "LockAcquire: lock [%u,%u] %s",
locktag->locktag_field1, locktag->locktag_field2,
- lock_mode_names[lockmode]);
+ lockMethodTable->lockModeNames[lockmode]);
#endif
- /* ugly */
- locktag->locktag_lockmethodid = lockmethodid;
-
- Assert(lockmethodid < NumLockMethods);
- lockMethodTable = LockMethods[lockmethodid];
- if (!lockMethodTable)
- elog(ERROR, "unrecognized lock method: %d", lockmethodid);
-
- /* Session locks and user locks are not transactional */
- if (!sessionLock && lockmethodid == DEFAULT_LOCKMETHOD)
+ /* Session locks are never transactional, else check table */
+ if (!sessionLock && lockMethodTable->transactional)
owner = CurrentResourceOwner;
else
owner = NULL;
localtag.lock = *locktag;
localtag.mode = lockmode;
- locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash[lockmethodid],
+ locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
(void *) &localtag,
HASH_ENTER, &found);
/*
* Otherwise we've got to mess with the shared lock table.
*/
- masterLock = lockMethodTable->masterLock;
+ masterLock = LockMgrLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE);
* pointer is valid, since a lock object with no locks can go away
* anytime.
*/
- lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid],
+ lock = (LOCK *) hash_search(LockMethodLockHash,
(void *) locktag,
HASH_ENTER_NULL, &found);
if (!lock)
/*
* Find or create a proclock entry with this tag
*/
- proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid],
+ proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
(void *) &proclocktag,
HASH_ENTER_NULL, &found);
if (!proclock)
* anyone to release the lock object later.
*/
Assert(SHMQueueEmpty(&(lock->procLocks)));
- if (!hash_search(LockMethodLockHash[lockmethodid],
+ if (!hash_search(LockMethodLockHash,
(void *) &(lock->tag),
HASH_REMOVE, NULL))
elog(PANIC, "lock table corrupted");
break; /* safe: we have a lock >= req level */
elog(LOG, "deadlock risk: raising lock level"
" from %s to %s on object %u/%u/%u",
- lock_mode_names[i], lock_mode_names[lockmode],
+ lockMethodTable->lockModeNames[i],
+ lockMethodTable->lockModeNames[lockmode],
lock->tag.locktag_field1, lock->tag.locktag_field2,
lock->tag.locktag_field3);
break;
*/
if (proclock->holdMask & LOCKBIT_ON(lockmode))
elog(ERROR, "lock %s on object %u/%u/%u is already held",
- lock_mode_names[lockmode],
+ lockMethodTable->lockModeNames[lockmode],
lock->tag.locktag_field1, lock->tag.locktag_field2,
lock->tag.locktag_field3);
{
SHMQueueDelete(&proclock->lockLink);
SHMQueueDelete(&proclock->procLink);
- if (!hash_search(LockMethodProcLockHash[lockmethodid],
+ if (!hash_search(LockMethodProcLockHash,
(void *) &(proclock->tag),
HASH_REMOVE, NULL))
elog(PANIC, "proclock table corrupted");
static void
RemoveLocalLock(LOCALLOCK *locallock)
{
- LOCKMETHODID lockmethodid = LOCALLOCK_LOCKMETHOD(*locallock);
-
pfree(locallock->lockOwners);
locallock->lockOwners = NULL;
- if (!hash_search(LockMethodLocalHash[lockmethodid],
+ if (!hash_search(LockMethodLocalHash,
(void *) &(locallock->tag),
HASH_REMOVE, NULL))
elog(WARNING, "locallock table corrupted");
PROCLOCK_PRINT("CleanUpLock: deleting", proclock);
SHMQueueDelete(&proclock->lockLink);
SHMQueueDelete(&proclock->procLink);
- if (!hash_search(LockMethodProcLockHash[lockmethodid],
+ if (!hash_search(LockMethodProcLockHash,
(void *) &(proclock->tag),
HASH_REMOVE, NULL))
elog(PANIC, "proclock table corrupted");
*/
LOCK_PRINT("CleanUpLock: deleting", lock, 0);
Assert(SHMQueueEmpty(&(lock->procLocks)));
- if (!hash_search(LockMethodLockHash[lockmethodid],
+ if (!hash_search(LockMethodLockHash,
(void *) &(lock->tag),
HASH_REMOVE, NULL))
elog(PANIC, "lock table corrupted");
char *new_status;
int len;
- Assert(lockmethodid < NumLockMethods);
-
LOCK_PRINT("WaitOnLock: sleeping on lock",
locallock->lock, locallock->tag.mode);
awaitedLock = NULL;
LOCK_PRINT("WaitOnLock: aborting on lock",
locallock->lock, locallock->tag.mode);
- LWLockRelease(lockMethodTable->masterLock);
+ LWLockRelease(LockMgrLock);
/*
* Now that we aren't holding the LockMgrLock, we can give an error
Assert(proc->links.next != INVALID_OFFSET);
Assert(waitLock);
Assert(waitLock->waitProcs.size > 0);
- Assert(0 < lockmethodid && lockmethodid < NumLockMethods);
+ Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
/* Remove proc from lock's wait queue */
SHMQueueDelete(&(proc->links));
}
/*
- * LockRelease -- look up 'locktag' in lock table 'lockmethodid' and
- * release one 'lockmode' lock on it. Release a session lock if
- * 'sessionLock' is true, else release a regular transaction lock.
+ * LockRelease -- look up 'locktag' and release one 'lockmode' lock on it.
+ * Release a session lock if 'sessionLock' is true, else release a
+ * regular transaction lock.
*
* Side Effects: find any waiting processes that are now wakable,
* grant them their requested locks and awaken them.
* come along and request the lock.)
*/
bool
-LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
- LOCKMODE lockmode, bool sessionLock)
+LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
{
+ LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
+ LockMethod lockMethodTable;
LOCALLOCKTAG localtag;
LOCALLOCK *locallock;
LOCK *lock;
PROCLOCK *proclock;
LWLockId masterLock;
- LockMethod lockMethodTable;
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 (Trace_userlocks && lockmethodid == USER_LOCKMETHOD)
- elog(LOG, "LockRelease: user lock [%u,%u] %s",
+ if (LOCK_DEBUG_ENABLED(locktag))
+ elog(LOG, "LockRelease: lock [%u,%u] %s",
locktag->locktag_field1, locktag->locktag_field2,
- lock_mode_names[lockmode]);
+ lockMethodTable->lockModeNames[lockmode]);
#endif
- /* ugly */
- locktag->locktag_lockmethodid = lockmethodid;
-
- Assert(lockmethodid < NumLockMethods);
- lockMethodTable = LockMethods[lockmethodid];
- if (!lockMethodTable)
- elog(ERROR, "unrecognized lock method: %d", lockmethodid);
-
/*
* Find the LOCALLOCK entry for this lock and lockmode
*/
localtag.lock = *locktag;
localtag.mode = lockmode;
- locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash[lockmethodid],
+ locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
(void *) &localtag,
HASH_FIND, NULL);
if (!locallock || locallock->nLocks <= 0)
{
elog(WARNING, "you don't own a lock of type %s",
- lock_mode_names[lockmode]);
+ lockMethodTable->lockModeNames[lockmode]);
return FALSE;
}
ResourceOwner owner;
int i;
- /* Session locks and user locks are not transactional */
- if (!sessionLock && lockmethodid == DEFAULT_LOCKMETHOD)
+ /* Session locks are never transactional, else check table */
+ if (!sessionLock && lockMethodTable->transactional)
owner = CurrentResourceOwner;
else
owner = NULL;
{
/* don't release a lock belonging to another owner */
elog(WARNING, "you don't own a lock of type %s",
- lock_mode_names[lockmode]);
+ lockMethodTable->lockModeNames[lockmode]);
return FALSE;
}
}
/*
* Otherwise we've got to mess with the shared lock table.
*/
- masterLock = lockMethodTable->masterLock;
+ masterLock = LockMgrLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE);
PROCLOCK_PRINT("LockRelease: WRONGTYPE", proclock);
LWLockRelease(masterLock);
elog(WARNING, "you don't own a lock of type %s",
- lock_mode_names[lockmode]);
+ lockMethodTable->lockModeNames[lockmode]);
RemoveLocalLock(locallock);
return FALSE;
}
PROCLOCK *proclock;
LOCK *lock;
+ if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
+ elog(ERROR, "unrecognized lock method: %d", lockmethodid);
+ lockMethodTable = LockMethods[lockmethodid];
+
#ifdef LOCK_DEBUG
- if (lockmethodid == USER_LOCKMETHOD ? Trace_userlocks : Trace_locks)
+ if (*(lockMethodTable->trace_flag))
elog(LOG, "LockReleaseAll: lockmethod=%d", lockmethodid);
#endif
- Assert(lockmethodid < NumLockMethods);
- lockMethodTable = LockMethods[lockmethodid];
- if (!lockMethodTable)
- elog(ERROR, "unrecognized lock method: %d", lockmethodid);
-
numLockModes = lockMethodTable->numLockModes;
- masterLock = lockMethodTable->masterLock;
+ masterLock = LockMgrLock;
/*
* First we run through the locallock table and get rid of unwanted
* pointing to the same proclock, and we daren't end up with any dangling
* pointers.
*/
- hash_seq_init(&status, LockMethodLocalHash[lockmethodid]);
+ hash_seq_init(&status, LockMethodLocalHash);
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
{
LWLockRelease(masterLock);
#ifdef LOCK_DEBUG
- if (lockmethodid == USER_LOCKMETHOD ? Trace_userlocks : Trace_locks)
+ if (*(lockMethodTable->trace_flag))
elog(LOG, "LockReleaseAll done");
#endif
}
/*
* LockReleaseCurrentOwner
* Release all locks belonging to CurrentResourceOwner
- *
- * Only DEFAULT_LOCKMETHOD locks can belong to a resource owner.
*/
void
LockReleaseCurrentOwner(void)
LOCALLOCKOWNER *lockOwners;
int i;
- hash_seq_init(&status, LockMethodLocalHash[DEFAULT_LOCKMETHOD]);
+ hash_seq_init(&status, LockMethodLocalHash);
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
{
/* Ignore items that must be nontransactional */
- if (LOCALLOCK_LOCKMETHOD(*locallock) != DEFAULT_LOCKMETHOD)
+ if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue;
/* Scan to see if there are any locks belonging to current owner */
/* We want to call LockRelease just once */
lockOwners[i].nLocks = 1;
locallock->nLocks = 1;
- if (!LockRelease(DEFAULT_LOCKMETHOD,
- &locallock->tag.lock,
+ if (!LockRelease(&locallock->tag.lock,
locallock->tag.mode,
false))
elog(WARNING, "LockReleaseCurrentOwner: failed??");
Assert(parent != NULL);
- hash_seq_init(&status, LockMethodLocalHash[DEFAULT_LOCKMETHOD]);
+ hash_seq_init(&status, LockMethodLocalHash);
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
{
int ip = -1;
/* Ignore items that must be nontransactional */
- if (LOCALLOCK_LOCKMETHOD(*locallock) != DEFAULT_LOCKMETHOD)
+ if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue;
/*
* Do the preparatory work for a PREPARE: make 2PC state file records
* for all locks currently held.
*
- * User locks are non-transactional and are therefore ignored.
+ * Non-transactional locks are ignored.
*
* There are some special cases that we error out on: we can't be holding
* any session locks (should be OK since only VACUUM uses those) and we
void
AtPrepare_Locks(void)
{
- LOCKMETHODID lockmethodid = DEFAULT_LOCKMETHOD;
HASH_SEQ_STATUS status;
LOCALLOCK *locallock;
* We don't need to touch shared memory for this --- all the necessary
* state information is in the locallock table.
*/
- hash_seq_init(&status, LockMethodLocalHash[lockmethodid]);
+ hash_seq_init(&status, LockMethodLocalHash);
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
{
LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
int i;
- /* Ignore items that are not of the lockmethod to be processed */
- if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)
+ /* Ignore nontransactional locks */
+ if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue;
/* Ignore it if we don't actually hold the lock */
PostPrepare_Locks(TransactionId xid)
{
PGPROC *newproc = TwoPhaseGetDummyProc(xid);
- LOCKMETHODID lockmethodid = DEFAULT_LOCKMETHOD;
HASH_SEQ_STATUS status;
SHM_QUEUE *procLocks = &(MyProc->procLocks);
LWLockId masterLock;
- LockMethod lockMethodTable;
- int numLockModes;
LOCALLOCK *locallock;
PROCLOCK *proclock;
PROCLOCKTAG proclocktag;
/* This is a critical section: any error means big trouble */
START_CRIT_SECTION();
- lockMethodTable = LockMethods[lockmethodid];
- if (!lockMethodTable)
- elog(ERROR, "unrecognized lock method: %d", lockmethodid);
-
- numLockModes = lockMethodTable->numLockModes;
- masterLock = lockMethodTable->masterLock;
+ masterLock = LockMgrLock;
/*
* First we run through the locallock table and get rid of unwanted
* pointing to the same proclock, and we daren't end up with any dangling
* pointers.
*/
- hash_seq_init(&status, LockMethodLocalHash[lockmethodid]);
+ hash_seq_init(&status, LockMethodLocalHash);
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
{
continue;
}
- /* Ignore items that are not of the lockmethod to be removed */
- if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)
+ /* Ignore nontransactional locks */
+ if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue;
/* We already checked there are no session locks */
lock = (LOCK *) MAKE_PTR(proclock->tag.lock);
- /* Ignore items that are not of the lockmethod to be removed */
- if (LOCK_LOCKMETHOD(*lock) != lockmethodid)
+ /* Ignore nontransactional locks */
+ if (!LockMethods[LOCK_LOCKMETHOD(*lock)]->transactional)
goto next_item;
PROCLOCK_PRINT("PostPrepare_Locks", proclock);
*/
SHMQueueDelete(&proclock->lockLink);
SHMQueueDelete(&proclock->procLink);
- if (!hash_search(LockMethodProcLockHash[lockmethodid],
+ if (!hash_search(LockMethodProcLockHash,
(void *) &(proclock->tag),
HASH_REMOVE, NULL))
elog(PANIC, "proclock table corrupted");
proclocktag.lock = MAKE_OFFSET(lock);
proclocktag.proc = MAKE_OFFSET(newproc);
- newproclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid],
+ newproclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
(void *) &proclocktag,
HASH_ENTER_NULL, &found);
if (!newproclock)
Size
LockShmemSize(void)
{
- Size size;
+ Size size = 0;
long max_table_size = NLOCKENTS();
- /* lock method headers */
- size = MAX_LOCK_METHODS * MAXALIGN(sizeof(LockMethodData));
-
/* lockHash table */
size = add_size(size, hash_estimate_size(max_table_size, sizeof(LOCK)));
LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
- proclockTable = LockMethodProcLockHash[DEFAULT_LOCKMETHOD];
+ proclockTable = LockMethodProcLockHash;
data->nelements = i = proclockTable->hctl->nentries;
/* Provide the textual name of any lock mode */
const char *
-GetLockmodeName(LOCKMODE mode)
+GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
{
- Assert(mode <= MAX_LOCKMODES);
- return lock_mode_names[mode];
+ Assert(lockmethodid > 0 && lockmethodid < lengthof(LockMethods));
+ Assert(mode > 0 && mode <= LockMethods[lockmethodid]->numLockModes);
+ return LockMethods[lockmethodid]->lockModeNames[mode];
}
#ifdef LOCK_DEBUG
/*
* Dump all locks in the given proc's procLocks list.
*
- * Must have already acquired the masterLock.
+ * Caller is responsible for having acquired appropriate LWLocks.
*/
void
DumpLocks(PGPROC *proc)
SHM_QUEUE *procLocks;
PROCLOCK *proclock;
LOCK *lock;
- int lockmethodid = DEFAULT_LOCKMETHOD;
- LockMethod lockMethodTable;
if (proc == NULL)
return;
procLocks = &proc->procLocks;
- Assert(lockmethodid < NumLockMethods);
- lockMethodTable = LockMethods[lockmethodid];
- if (!lockMethodTable)
- return;
-
if (proc->waitLock)
LOCK_PRINT("DumpLocks: waiting on", proc->waitLock, 0);
}
/*
- * Dump all postgres locks. Must have already acquired the masterLock.
+ * Dump all lmgr locks.
+ *
+ * Caller is responsible for having acquired appropriate LWLocks.
*/
void
DumpAllLocks(void)
PGPROC *proc;
PROCLOCK *proclock;
LOCK *lock;
- int lockmethodid = DEFAULT_LOCKMETHOD;
- LockMethod lockMethodTable;
HTAB *proclockTable;
HASH_SEQ_STATUS status;
proc = MyProc;
- if (proc == NULL)
- return;
-
- Assert(lockmethodid < NumLockMethods);
- lockMethodTable = LockMethods[lockmethodid];
- if (!lockMethodTable)
- return;
-
- proclockTable = LockMethodProcLockHash[lockmethodid];
+ proclockTable = LockMethodProcLockHash;
- if (proc->waitLock)
+ if (proc && proc->waitLock)
LOCK_PRINT("DumpAllLocks: waiting on", proc->waitLock, 0);
hash_seq_init(&status, proclockTable);
lockmode = rec->lockmode;
lockmethodid = locktag->locktag_lockmethodid;
- Assert(lockmethodid < NumLockMethods);
- lockMethodTable = LockMethods[lockmethodid];
- if (!lockMethodTable)
+ if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
elog(ERROR, "unrecognized lock method: %d", lockmethodid);
+ lockMethodTable = LockMethods[lockmethodid];
- masterLock = lockMethodTable->masterLock;
+ masterLock = LockMgrLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE);
/*
* Find or create a lock with this tag.
*/
- lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid],
+ lock = (LOCK *) hash_search(LockMethodLockHash,
(void *) locktag,
HASH_ENTER_NULL, &found);
if (!lock)
/*
* Find or create a proclock entry with this tag
*/
- proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid],
+ proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
(void *) &proclocktag,
HASH_ENTER_NULL, &found);
if (!proclock)
* anyone to release the lock object later.
*/
Assert(SHMQueueEmpty(&(lock->procLocks)));
- if (!hash_search(LockMethodLockHash[lockmethodid],
+ if (!hash_search(LockMethodLockHash,
(void *) &(lock->tag),
HASH_REMOVE, NULL))
elog(PANIC, "lock table corrupted");
*/
if (proclock->holdMask & LOCKBIT_ON(lockmode))
elog(ERROR, "lock %s on object %u/%u/%u is already held",
- lock_mode_names[lockmode],
+ lockMethodTable->lockModeNames[lockmode],
lock->tag.locktag_field1, lock->tag.locktag_field2,
lock->tag.locktag_field3);
lockmode = rec->lockmode;
lockmethodid = locktag->locktag_lockmethodid;
- Assert(lockmethodid < NumLockMethods);
- lockMethodTable = LockMethods[lockmethodid];
- if (!lockMethodTable)
+ if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
elog(ERROR, "unrecognized lock method: %d", lockmethodid);
+ lockMethodTable = LockMethods[lockmethodid];
- masterLock = lockMethodTable->masterLock;
+ masterLock = LockMgrLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE);
/*
* Re-find the lock object (it had better be there).
*/
- lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid],
+ lock = (LOCK *) hash_search(LockMethodLockHash,
(void *) locktag,
HASH_FIND, NULL);
if (!lock)
MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG)); /* must clear padding */
proclocktag.lock = MAKE_OFFSET(lock);
proclocktag.proc = MAKE_OFFSET(proc);
- proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid],
+ proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
(void *) &proclocktag,
HASH_FIND, NULL);
if (!proclock)
PROCLOCK_PRINT("lock_twophase_postcommit: WRONGTYPE", proclock);
LWLockRelease(masterLock);
elog(WARNING, "you don't own a lock of type %s",
- lock_mode_names[lockmode]);
+ lockMethodTable->lockModeNames[lockmode]);
return;
}
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.91 2005/10/15 02:49:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.92 2005/12/09 01:22:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define LOCKBIT_ON(lockmode) (1 << (lockmode))
#define LOCKBIT_OFF(lockmode) (~(1 << (lockmode)))
-/*
- * There is normally only one lock method, the default one.
- * If user locks are enabled, an additional lock method is present.
- * Lock methods are identified by LOCKMETHODID. (Despite the declaration as
- * uint16, we are constrained to 256 lockmethods by the layout of LOCKTAG.)
- */
-typedef uint16 LOCKMETHODID;
-
-/* MAX_LOCK_METHODS is the number of distinct lock control tables allowed */
-#define MAX_LOCK_METHODS 3
-
-#define INVALID_LOCKMETHOD 0
-#define DEFAULT_LOCKMETHOD 1
-#define USER_LOCKMETHOD 2
-
-#define LockMethodIsValid(lockmethodid) ((lockmethodid) != INVALID_LOCKMETHOD)
-
-extern int NumLockMethods;
-
/*
- * This is the control structure for a lock table. It lives in shared
- * memory. Currently, none of these fields change after startup. In addition
- * to the LockMethodData, a lock table has a shared "lockHash" table holding
- * per-locked-object lock information, and a shared "proclockHash" table
- * holding per-lock-holder/waiter lock information.
+ * This data structure defines the locking semantics associated with a
+ * "lock method". The semantics specify the meaning of each lock mode
+ * (by defining which lock modes it conflicts with), and also whether locks
+ * of this method are transactional (ie, are released at transaction end).
+ * All of this data is constant and is kept in const tables.
*
- * masterLock -- LWLock used to synchronize access to the table
+ * numLockModes -- number of lock modes (READ,WRITE,etc) that
+ * are defined in this lock method. Must be less than MAX_LOCKMODES.
*
- * numLockModes -- number of lock types (READ,WRITE,etc) that
- * are defined on this lock table
+ * transactional -- TRUE if locks are released automatically at xact end.
*
* conflictTab -- this is an array of bitmasks showing lock
- * type conflicts. conflictTab[i] is a mask with the j-th bit
- * turned on if lock types i and j conflict.
+ * mode conflicts. conflictTab[i] is a mask with the j-th bit
+ * turned on if lock modes i and j conflict. Lock modes are
+ * numbered 1..numLockModes; conflictTab[0] is unused.
+ *
+ * lockModeNames -- ID strings for debug printouts.
+ *
+ * trace_flag -- pointer to GUC trace flag for this lock method.
*/
typedef struct LockMethodData
{
- LWLockId masterLock;
int numLockModes;
- LOCKMASK conflictTab[MAX_LOCKMODES];
+ bool transactional;
+ const LOCKMASK *conflictTab;
+ const char * const *lockModeNames;
+ const bool *trace_flag;
} LockMethodData;
-typedef LockMethodData *LockMethod;
+typedef const LockMethodData *LockMethod;
+
+/*
+ * Lock methods are identified by LOCKMETHODID. (Despite the declaration as
+ * uint16, we are constrained to 256 lockmethods by the layout of LOCKTAG.)
+ */
+typedef uint16 LOCKMETHODID;
+
+/* These identify the known lock methods */
+#define DEFAULT_LOCKMETHOD 1
+#define USER_LOCKMETHOD 2
+
+/*
+ * These are the valid values of type LOCKMODE for all the standard lock
+ * methods (both DEFAULT and USER).
+ */
+
+/* NoLock is not a lock mode, but a flag value meaning "don't get a lock" */
+#define NoLock 0
+
+#define AccessShareLock 1 /* SELECT */
+#define RowShareLock 2 /* SELECT FOR UPDATE/FOR SHARE */
+#define RowExclusiveLock 3 /* INSERT, UPDATE, DELETE */
+#define ShareUpdateExclusiveLock 4 /* VACUUM (non-FULL) */
+#define ShareLock 5 /* CREATE INDEX */
+#define ShareRowExclusiveLock 6 /* like EXCLUSIVE MODE, but allows ROW
+ * SHARE */
+#define ExclusiveLock 7 /* blocks ROW SHARE/SELECT...FOR
+ * UPDATE */
+#define AccessExclusiveLock 8 /* ALTER TABLE, DROP TABLE, VACUUM
+ * FULL, and unqualified LOCK TABLE */
/*
* to widen Oid, BlockNumber, or TransactionId to more than 32 bits.
*
* We include lockmethodid in the locktag so that a single hash table in
- * shared memory can store locks of different lockmethods. For largely
- * historical reasons, it's passed to the lock.c routines as a separate
- * argument and then stored into the locktag.
+ * shared memory can store locks of different lockmethods.
*/
typedef struct LOCKTAG
{
(locktag).locktag_field2 = (reloid), \
(locktag).locktag_field3 = 0, \
(locktag).locktag_field4 = 0, \
- (locktag).locktag_type = LOCKTAG_RELATION)
+ (locktag).locktag_type = LOCKTAG_RELATION, \
+ (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
#define SET_LOCKTAG_RELATION_EXTEND(locktag,dboid,reloid) \
((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (reloid), \
(locktag).locktag_field3 = 0, \
(locktag).locktag_field4 = 0, \
- (locktag).locktag_type = LOCKTAG_RELATION_EXTEND)
+ (locktag).locktag_type = LOCKTAG_RELATION_EXTEND, \
+ (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
#define SET_LOCKTAG_PAGE(locktag,dboid,reloid,blocknum) \
((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (reloid), \
(locktag).locktag_field3 = (blocknum), \
(locktag).locktag_field4 = 0, \
- (locktag).locktag_type = LOCKTAG_PAGE)
+ (locktag).locktag_type = LOCKTAG_PAGE, \
+ (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
#define SET_LOCKTAG_TUPLE(locktag,dboid,reloid,blocknum,offnum) \
((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (reloid), \
(locktag).locktag_field3 = (blocknum), \
(locktag).locktag_field4 = (offnum), \
- (locktag).locktag_type = LOCKTAG_TUPLE)
+ (locktag).locktag_type = LOCKTAG_TUPLE, \
+ (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
#define SET_LOCKTAG_TRANSACTION(locktag,xid) \
((locktag).locktag_field1 = (xid), \
(locktag).locktag_field2 = 0, \
(locktag).locktag_field3 = 0, \
(locktag).locktag_field4 = 0, \
- (locktag).locktag_type = LOCKTAG_TRANSACTION)
+ (locktag).locktag_type = LOCKTAG_TRANSACTION, \
+ (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
#define SET_LOCKTAG_OBJECT(locktag,dboid,classoid,objoid,objsubid) \
((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (classoid), \
(locktag).locktag_field3 = (objoid), \
(locktag).locktag_field4 = (objsubid), \
- (locktag).locktag_type = LOCKTAG_OBJECT)
+ (locktag).locktag_type = LOCKTAG_OBJECT, \
+ (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
/*
* function prototypes
*/
extern void InitLocks(void);
-extern LockMethod GetLocksMethodTable(LOCK *lock);
-extern LOCKMETHODID LockMethodTableInit(const char *tabName,
- const LOCKMASK *conflictsP,
- int numModes);
-extern LOCKMETHODID LockMethodTableRename(LOCKMETHODID lockmethodid);
-extern LockAcquireResult LockAcquire(LOCKMETHODID lockmethodid,
- LOCKTAG *locktag,
+extern LockMethod GetLocksMethodTable(const LOCK *lock);
+extern LockAcquireResult LockAcquire(const LOCKTAG *locktag,
bool isTempObject,
LOCKMODE lockmode,
bool sessionLock,
bool dontWait);
-extern bool LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
+extern bool LockRelease(const LOCKTAG *locktag,
LOCKMODE lockmode, bool sessionLock);
extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
extern void LockReleaseCurrentOwner(void);
PGPROC *proc2);
extern void InitDeadLockChecking(void);
extern LockData *GetLockStatusData(void);
-extern const char *GetLockmodeName(LOCKMODE mode);
+extern const char *GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode);
extern void lock_twophase_recover(TransactionId xid, uint16 info,
void *recdata, uint32 len);