aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/userlock/user_locks.c7
-rw-r--r--src/backend/storage/ipc/ipci.c5
-rw-r--r--src/backend/storage/lmgr/README27
-rw-r--r--src/backend/storage/lmgr/deadlock.c5
-rw-r--r--src/backend/storage/lmgr/lmgr.c142
-rw-r--r--src/backend/storage/lmgr/lock.c596
-rw-r--r--src/backend/storage/lmgr/proc.c4
-rw-r--r--src/backend/utils/adt/lockfuncs.c5
-rw-r--r--src/backend/utils/cache/relcache.c4
-rw-r--r--src/include/storage/lmgr.h25
-rw-r--r--src/include/storage/lock.h119
-rw-r--r--src/tools/backend/index.html33
12 files changed, 396 insertions, 576 deletions
diff --git a/contrib/userlock/user_locks.c b/contrib/userlock/user_locks.c
index 0cfc5a2d861..53c48bf0a7f 100644
--- a/contrib/userlock/user_locks.c
+++ b/contrib/userlock/user_locks.c
@@ -23,7 +23,8 @@
(locktag).locktag_field2 = (id1), \
(locktag).locktag_field3 = (id2), \
(locktag).locktag_field4 = 0, \
- (locktag).locktag_type = LOCKTAG_USERLOCK)
+ (locktag).locktag_type = LOCKTAG_USERLOCK, \
+ (locktag).locktag_lockmethodid = USER_LOCKMETHOD)
int
@@ -33,7 +34,7 @@ user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode)
SET_LOCKTAG_USERLOCK(tag, id1, id2);
- return (LockAcquire(USER_LOCKMETHOD, &tag, false,
+ return (LockAcquire(&tag, false,
lockmode, true, true) != LOCKACQUIRE_NOT_AVAIL);
}
@@ -44,7 +45,7 @@ user_unlock(uint32 id1, uint32 id2, LOCKMODE lockmode)
SET_LOCKTAG_USERLOCK(tag, id1, id2);
- return LockRelease(USER_LOCKMETHOD, &tag, lockmode, true);
+ return LockRelease(&tag, lockmode, true);
}
int
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 997c38a45c8..bfe8d52af30 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.79 2005/10/15 02:49:25 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.80 2005/12/09 01:22:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,7 +25,7 @@
#include "storage/bufmgr.h"
#include "storage/freespace.h"
#include "storage/ipc.h"
-#include "storage/lmgr.h"
+#include "storage/lock.h"
#include "storage/lwlock.h"
#include "storage/pg_sema.h"
#include "storage/pg_shmem.h"
@@ -159,7 +159,6 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
* Set up lock manager
*/
InitLocks();
- InitLockTable();
/*
* Set up process table
diff --git a/src/backend/storage/lmgr/README b/src/backend/storage/lmgr/README
index 943b2f5bc03..25820f4b73d 100644
--- a/src/backend/storage/lmgr/README
+++ b/src/backend/storage/lmgr/README
@@ -1,4 +1,4 @@
-$PostgreSQL: pgsql/src/backend/storage/lmgr/README,v 1.17 2005/06/14 22:15:32 tgl Exp $
+$PostgreSQL: pgsql/src/backend/storage/lmgr/README,v 1.18 2005/12/09 01:22:04 tgl Exp $
LOCKING OVERVIEW
@@ -151,7 +151,7 @@ tag -
SHMEM offset of the LOCK object this PROCLOCK is for.
tag.proc
- SHMEM offset of PROC of backend process that owns this PROCLOCK.
+ SHMEM offset of PGPROC of backend process that owns this PROCLOCK.
holdMask -
A bitmask for the lock types successfully acquired by this PROCLOCK.
@@ -415,3 +415,26 @@ seems a safer approach than trying to allocate workspace on the fly; we
don't want to risk having the deadlock detector run out of memory, else
we really have no guarantees at all that deadlock will be detected.
+
+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.
+
+The lockmode parameter can have the same values as for normal locks although
+probably only ExclusiveLock can have some practical use.
+
+ DZ - 22 Nov 1997
diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c
index 3a2cdd82a09..adbd373bb7f 100644
--- a/src/backend/storage/lmgr/deadlock.c
+++ b/src/backend/storage/lmgr/deadlock.c
@@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.36 2005/10/29 00:31:51 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.37 2005/12/09 01:22:04 tgl Exp $
*
* Interface:
*
@@ -930,7 +930,8 @@ DeadLockReport(void)
appendStringInfo(&buf,
_("Process %d waits for %s on %s; blocked by process %d."),
info->pid,
- GetLockmodeName(info->lockmode),
+ GetLockmodeName(info->locktag.locktag_lockmethodid,
+ info->lockmode),
buf2.data,
nextpid);
}
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 8ffeced9979..60e374959b0 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -18,7 +18,6 @@
#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"
@@ -26,89 +25,6 @@
/*
- * 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.
*
@@ -141,8 +57,7 @@ LockRelation(Relation relation, LOCKMODE lockmode)
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
@@ -178,8 +93,7 @@ ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
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;
@@ -213,7 +127,7 @@ UnlockRelation(Relation relation, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
- LockRelease(LockTableId, &tag, lockmode, false);
+ LockRelease(&tag, lockmode, false);
}
/*
@@ -235,8 +149,7 @@ LockRelationForSession(LockRelId *relid, bool istemprel, LOCKMODE lockmode)
SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
- (void) LockAcquire(LockTableId, &tag, istemprel,
- lockmode, true, false);
+ (void) LockAcquire(&tag, istemprel, lockmode, true, false);
}
/*
@@ -249,7 +162,7 @@ UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
- LockRelease(LockTableId, &tag, lockmode, true);
+ LockRelease(&tag, lockmode, true);
}
/*
@@ -271,8 +184,7 @@ LockRelationForExtension(Relation relation, LOCKMODE lockmode)
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);
}
/*
@@ -287,7 +199,7 @@ UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
- LockRelease(LockTableId, &tag, lockmode, false);
+ LockRelease(&tag, lockmode, false);
}
/*
@@ -306,8 +218,7 @@ LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
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);
}
/*
@@ -326,7 +237,7 @@ ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
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);
}
@@ -343,7 +254,7 @@ UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.relId,
blkno);
- LockRelease(LockTableId, &tag, lockmode, false);
+ LockRelease(&tag, lockmode, false);
}
/*
@@ -364,8 +275,7 @@ LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid));
- (void) LockAcquire(LockTableId, &tag, relation->rd_istemp,
- lockmode, false, false);
+ (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
}
/*
@@ -385,7 +295,7 @@ ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid));
- return (LockAcquire(LockTableId, &tag, relation->rd_istemp,
+ return (LockAcquire(&tag, relation->rd_istemp,
lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
}
@@ -403,7 +313,7 @@ UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid));
- LockRelease(LockTableId, &tag, lockmode, false);
+ LockRelease(&tag, lockmode, false);
}
/*
@@ -420,8 +330,7 @@ XactLockTableInsert(TransactionId xid)
SET_LOCKTAG_TRANSACTION(tag, xid);
- (void) LockAcquire(LockTableId, &tag, false,
- ExclusiveLock, false, false);
+ (void) LockAcquire(&tag, false, ExclusiveLock, false, false);
}
/*
@@ -439,7 +348,7 @@ XactLockTableDelete(TransactionId xid)
SET_LOCKTAG_TRANSACTION(tag, xid);
- LockRelease(LockTableId, &tag, ExclusiveLock, false);
+ LockRelease(&tag, ExclusiveLock, false);
}
/*
@@ -466,10 +375,9 @@ XactLockTableWait(TransactionId xid)
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;
@@ -502,11 +410,11 @@ ConditionalXactLockTableWait(TransactionId xid)
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;
@@ -545,8 +453,7 @@ LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
objid,
objsubid);
- (void) LockAcquire(LockTableId, &tag, false,
- lockmode, false, false);
+ (void) LockAcquire(&tag, false, lockmode, false, false);
}
/*
@@ -564,7 +471,7 @@ UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
objid,
objsubid);
- LockRelease(LockTableId, &tag, lockmode, false);
+ LockRelease(&tag, lockmode, false);
}
/*
@@ -584,8 +491,7 @@ LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
objid,
objsubid);
- (void) LockAcquire(LockTableId, &tag, false,
- lockmode, false, false);
+ (void) LockAcquire(&tag, false, lockmode, false, false);
}
/*
@@ -603,5 +509,5 @@ UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
objid,
objsubid);
- LockRelease(LockTableId, &tag, lockmode, false);
+ LockRelease(&tag, lockmode, false);
}
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index d703432563c..344d677cd2f 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -8,11 +8,10 @@
*
*
* 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.
@@ -22,8 +21,8 @@
*
* Interface:
*
- * LockAcquire(), LockRelease(), LockMethodTableInit(),
- * LockMethodTableRename(), LockReleaseAll(),
+ * InitLocks(), GetLocksMethodTable(),
+ * LockAcquire(), LockRelease(), LockReleaseAll(),
* LockCheckConflicts(), GrantLock()
*
*-------------------------------------------------------------------------
@@ -50,31 +49,54 @@ int max_locks_per_xact; /* set by guc.c */
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",
@@ -88,6 +110,70 @@ static const char *const lock_mode_names[] =
"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
@@ -116,21 +202,20 @@ bool Debug_deadlocks = false;
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 "
@@ -146,14 +231,15 @@ LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
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,
@@ -178,107 +264,21 @@ static void CleanUpLock(LOCKMETHODID lockmethodid, LOCK *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.
@@ -289,15 +289,15 @@ LockMethodTableInit(const char *tabName,
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
@@ -308,15 +308,15 @@ LockMethodTableInit(const char *tabName,
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
@@ -327,62 +327,39 @@ LockMethodTableInit(const char *tabName,
* 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)
@@ -403,43 +380,16 @@ LockMethodTableRename(LOCKMETHODID lockmethodid)
*
* 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;
@@ -448,26 +398,23 @@ LockAcquire(LOCKMETHODID lockmethodid,
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;
@@ -479,7 +426,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
localtag.lock = *locktag;
localtag.mode = lockmode;
- locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash[lockmethodid],
+ locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
(void *) &localtag,
HASH_ENTER, &found);
@@ -527,7 +474,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
/*
* Otherwise we've got to mess with the shared lock table.
*/
- masterLock = lockMethodTable->masterLock;
+ masterLock = LockMgrLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE);
@@ -539,7 +486,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
* 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)
@@ -585,7 +532,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
/*
* 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)
@@ -600,7 +547,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
* 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");
@@ -657,7 +604,8 @@ LockAcquire(LOCKMETHODID lockmethodid,
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;
@@ -682,7 +630,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
*/
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);
@@ -718,7 +666,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
{
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");
@@ -779,11 +727,9 @@ LockAcquire(LOCKMETHODID lockmethodid,
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");
@@ -964,7 +910,7 @@ CleanUpLock(LOCKMETHODID lockmethodid, LOCK *lock, PROCLOCK *proclock,
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");
@@ -978,7 +924,7 @@ CleanUpLock(LOCKMETHODID lockmethodid, LOCK *lock, PROCLOCK *proclock,
*/
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");
@@ -1053,8 +999,6 @@ WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,
char *new_status;
int len;
- Assert(lockmethodid < NumLockMethods);
-
LOCK_PRINT("WaitOnLock: sleeping on lock",
locallock->lock, locallock->tag.mode);
@@ -1092,7 +1036,7 @@ WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,
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
@@ -1131,7 +1075,7 @@ RemoveFromWaitQueue(PGPROC *proc)
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));
@@ -1162,9 +1106,9 @@ RemoveFromWaitQueue(PGPROC *proc)
}
/*
- * 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.
@@ -1173,32 +1117,30 @@ RemoveFromWaitQueue(PGPROC *proc)
* 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
*/
@@ -1206,7 +1148,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
localtag.lock = *locktag;
localtag.mode = lockmode;
- locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash[lockmethodid],
+ locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
(void *) &localtag,
HASH_FIND, NULL);
@@ -1216,7 +1158,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
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;
}
@@ -1228,8 +1170,8 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
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;
@@ -1253,7 +1195,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
{
/* 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;
}
}
@@ -1270,7 +1212,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
/*
* Otherwise we've got to mess with the shared lock table.
*/
- masterLock = lockMethodTable->masterLock;
+ masterLock = LockMgrLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE);
@@ -1293,7 +1235,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
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;
}
@@ -1332,18 +1274,17 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
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
@@ -1352,7 +1293,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
* 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)
{
@@ -1480,7 +1421,7 @@ next_item:
LWLockRelease(masterLock);
#ifdef LOCK_DEBUG
- if (lockmethodid == USER_LOCKMETHOD ? Trace_userlocks : Trace_locks)
+ if (*(lockMethodTable->trace_flag))
elog(LOG, "LockReleaseAll done");
#endif
}
@@ -1488,8 +1429,6 @@ next_item:
/*
* LockReleaseCurrentOwner
* Release all locks belonging to CurrentResourceOwner
- *
- * Only DEFAULT_LOCKMETHOD locks can belong to a resource owner.
*/
void
LockReleaseCurrentOwner(void)
@@ -1499,12 +1438,12 @@ 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 */
@@ -1532,8 +1471,7 @@ LockReleaseCurrentOwner(void)
/* 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??");
@@ -1559,7 +1497,7 @@ LockReassignCurrentOwner(void)
Assert(parent != NULL);
- hash_seq_init(&status, LockMethodLocalHash[DEFAULT_LOCKMETHOD]);
+ hash_seq_init(&status, LockMethodLocalHash);
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
{
@@ -1568,7 +1506,7 @@ LockReassignCurrentOwner(void)
int ip = -1;
/* Ignore items that must be nontransactional */
- if (LOCALLOCK_LOCKMETHOD(*locallock) != DEFAULT_LOCKMETHOD)
+ if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue;
/*
@@ -1610,7 +1548,7 @@ LockReassignCurrentOwner(void)
* 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
@@ -1621,7 +1559,6 @@ LockReassignCurrentOwner(void)
void
AtPrepare_Locks(void)
{
- LOCKMETHODID lockmethodid = DEFAULT_LOCKMETHOD;
HASH_SEQ_STATUS status;
LOCALLOCK *locallock;
@@ -1629,7 +1566,7 @@ AtPrepare_Locks(void)
* 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)
{
@@ -1637,8 +1574,8 @@ AtPrepare_Locks(void)
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 */
@@ -1689,12 +1626,9 @@ void
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;
@@ -1704,12 +1638,7 @@ PostPrepare_Locks(TransactionId xid)
/* 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
@@ -1720,7 +1649,7 @@ PostPrepare_Locks(TransactionId xid)
* 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)
{
@@ -1735,8 +1664,8 @@ PostPrepare_Locks(TransactionId xid)
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 */
@@ -1768,8 +1697,8 @@ PostPrepare_Locks(TransactionId xid)
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);
@@ -1798,7 +1727,7 @@ PostPrepare_Locks(TransactionId xid)
*/
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");
@@ -1810,7 +1739,7 @@ PostPrepare_Locks(TransactionId xid)
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)
@@ -1859,12 +1788,9 @@ next_item:
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)));
@@ -1910,7 +1836,7 @@ GetLockStatusData(void)
LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
- proclockTable = LockMethodProcLockHash[DEFAULT_LOCKMETHOD];
+ proclockTable = LockMethodProcLockHash;
data->nelements = i = proclockTable->hctl->nentries;
@@ -1944,17 +1870,18 @@ GetLockStatusData(void)
/* 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)
@@ -1962,19 +1889,12 @@ 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);
@@ -1996,7 +1916,9 @@ DumpLocks(PGPROC *proc)
}
/*
- * 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)
@@ -2004,23 +1926,13 @@ 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);
@@ -2071,19 +1983,18 @@ lock_twophase_recover(TransactionId xid, uint16 info,
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)
@@ -2128,7 +2039,7 @@ lock_twophase_recover(TransactionId xid, uint16 info,
/*
* 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)
@@ -2143,7 +2054,7 @@ lock_twophase_recover(TransactionId xid, uint16 info,
* 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");
@@ -2186,7 +2097,7 @@ lock_twophase_recover(TransactionId xid, uint16 info,
*/
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);
@@ -2224,19 +2135,18 @@ lock_twophase_postcommit(TransactionId xid, uint16 info,
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)
@@ -2248,7 +2158,7 @@ lock_twophase_postcommit(TransactionId xid, uint16 info,
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)
@@ -2263,7 +2173,7 @@ lock_twophase_postcommit(TransactionId xid, uint16 info,
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;
}
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 072059d3d4c..8d8269041e7 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.168 2005/11/22 18:17:21 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.169 2005/12/09 01:22:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -630,7 +630,7 @@ ProcSleep(LockMethod lockMethodTable,
LOCK *lock,
PROCLOCK *proclock)
{
- LWLockId masterLock = lockMethodTable->masterLock;
+ LWLockId masterLock = LockMgrLock;
PROC_QUEUE *waitQueue = &(lock->waitProcs);
LOCKMASK myHeldLocks = MyProc->heldLocks;
bool early_deadlock = false;
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index bf7ee788c42..368822d3934 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -6,7 +6,7 @@
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.20 2005/10/15 02:49:28 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.21 2005/12/09 01:22:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -256,7 +256,8 @@ pg_lock_status(PG_FUNCTION_ARGS)
else
nulls[10] = 'n';
values[11] = DirectFunctionCall1(textin,
- CStringGetDatum(GetLockmodeName(mode)));
+ CStringGetDatum(GetLockmodeName(LOCK_LOCKMETHOD(*lock),
+ mode)));
values[12] = BoolGetDatum(granted);
tuple = heap_formtuple(funcctx->tuple_desc, values, nulls);
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 7ad8f7d0241..9854291df8c 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.232 2005/11/22 18:17:24 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.233 2005/12/09 01:22:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3362,7 +3362,7 @@ RelationIdIsInInitFile(Oid relationId)
* just after sending them. The unlink before ensures that a backend that's
* currently starting cannot read the now-obsolete init file and then miss
* the SI messages that will force it to update its relcache entries. (This
- * works because the backend startup sequence gets into the PROC array before
+ * works because the backend startup sequence gets into the PGPROC array before
* trying to load the init file.) The unlink after is to synchronize with a
* backend that may currently be trying to write an init file based on data
* that we've just rendered invalid. Such a backend will see the SI messages,
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index 730060a3480..3e64dea91f8 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.52 2005/10/15 02:49:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.53 2005/12/09 01:22:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,29 +18,6 @@
#include "utils/rel.h"
-/* These are the valid values of type LOCKMODE: */
-
-/* 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 */
-
-/*
- * Note: all lock mode numbers must be less than lock.h's MAX_LOCKMODES,
- * so increase that if you want to add more modes.
- */
-
-extern void InitLockTable(void);
extern void RelationInitLockInfo(Relation relation);
/* Lock a relation */
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index e6b9e94b657..e289632054c 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -55,50 +55,68 @@ typedef int LOCKMODE;
#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 */
/*
@@ -138,9 +156,7 @@ typedef enum LockTagType
* 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
{
@@ -162,42 +178,48 @@ 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)
/*
@@ -366,18 +388,13 @@ typedef enum
* 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);
@@ -399,7 +416,7 @@ extern void RememberSimpleDeadLock(PGPROC *proc1,
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);
diff --git a/src/tools/backend/index.html b/src/tools/backend/index.html
index af255f912fe..db531744653 100644
--- a/src/tools/backend/index.html
+++ b/src/tools/backend/index.html
@@ -128,31 +128,16 @@ Block</a> - data/index buffer cache block</li>
addresses using table name and block number( <a
href="../../include/storage/buf_internals.h">BufferTag</a>)</li>
-<li>MultiLevelLockTable (ctl) - control structure for each locking
-method. Currently, only multi-level locking is used(<a
-href="../../include/storage/lock.h">LOCKMETHODCTL</a>).</li>
-
-<li>MultiLevelLockTable (lock hash) - the <a
+<li>Lock Manager Tables (lock hash) - the <a
href="../../include/storage/lock.h">LOCK</a> structure, looked up
-using relation, database object ids(<a
-href="../../include/storage/lock.h">LOCKTAG)</a>. The lock table
-structure contains the lock modes(read/write or shared/exclusive)
-and circular linked list of backends (<a
-href="../../include/storage/proc.h">PROC</a> structure pointers)
-waiting on the lock.</li>
-
-<li>MultiLevelLockTable (xid hash) - lookup of LOCK structure
-address using transaction id, LOCK address. It is used to quickly
-check if the current transaction already has any locks on a table,
-rather than having to search through all the held locks. It also
-stores the modes (read/write) of the locks held by the current
-transaction. The returned <a
-href="../../include/storage/lock.h">XIDLookupEnt</a> structure also
-contains a pointer to the backend's PROC.lockQueue.</li>
-
-<li><a href="../../include/storage/proc.h">Proc Header</a> -
-information about each backend, including locks held/waiting,
-indexed by process id</li>
+using a <a href="../../include/storage/lock.h">LOCKTAG</a>.
+A LOCK structure exists for each lockable object that is currently
+locked by any backend. Also, there is a subsidiary <a
+href="../../include/storage/lock.h">PROCLOCK</a> structure for each
+backend currently interested in a given LOCK</li>
+
+<li><a href="../../include/storage/proc.h">PGPROC Structures</a> -
+information about each backend, including locks held/waiting</li>
</ul>
<p>Each data structure is created by calling <a