Commit c599a247 authored by Tom Lane's avatar Tom Lane

Simplify lock manager data structures by making a clear separation between

the data defining the semantics of a lock method (ie, conflict resolution
table and ancillary data, which is all constant) and the hash tables
storing the current state.  The only thing we give up by this is the
ability to use separate hashtables for different lock methods, but there
is no need for that anyway.  Put some extra fields into the LockMethod
definition structs to clean up some other uglinesses, like hard-wired
tests for DEFAULT_LOCKMETHOD and USER_LOCKMETHOD.  This commit doesn't
do anything about the performance issues we were discussing, but it clears
away some of the underbrush that's in the way of fixing that.
parent 34848052
...@@ -23,7 +23,8 @@ ...@@ -23,7 +23,8 @@
(locktag).locktag_field2 = (id1), \ (locktag).locktag_field2 = (id1), \
(locktag).locktag_field3 = (id2), \ (locktag).locktag_field3 = (id2), \
(locktag).locktag_field4 = 0, \ (locktag).locktag_field4 = 0, \
(locktag).locktag_type = LOCKTAG_USERLOCK) (locktag).locktag_type = LOCKTAG_USERLOCK, \
(locktag).locktag_lockmethodid = USER_LOCKMETHOD)
int int
...@@ -33,7 +34,7 @@ user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode) ...@@ -33,7 +34,7 @@ user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode)
SET_LOCKTAG_USERLOCK(tag, id1, id2); SET_LOCKTAG_USERLOCK(tag, id1, id2);
return (LockAcquire(USER_LOCKMETHOD, &tag, false, return (LockAcquire(&tag, false,
lockmode, true, true) != LOCKACQUIRE_NOT_AVAIL); lockmode, true, true) != LOCKACQUIRE_NOT_AVAIL);
} }
...@@ -44,7 +45,7 @@ user_unlock(uint32 id1, uint32 id2, LOCKMODE lockmode) ...@@ -44,7 +45,7 @@ user_unlock(uint32 id1, uint32 id2, LOCKMODE lockmode)
SET_LOCKTAG_USERLOCK(tag, id1, id2); SET_LOCKTAG_USERLOCK(tag, id1, id2);
return LockRelease(USER_LOCKMETHOD, &tag, lockmode, true); return LockRelease(&tag, lockmode, true);
} }
int int
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -25,7 +25,7 @@
#include "storage/bufmgr.h" #include "storage/bufmgr.h"
#include "storage/freespace.h" #include "storage/freespace.h"
#include "storage/ipc.h" #include "storage/ipc.h"
#include "storage/lmgr.h" #include "storage/lock.h"
#include "storage/lwlock.h" #include "storage/lwlock.h"
#include "storage/pg_sema.h" #include "storage/pg_sema.h"
#include "storage/pg_shmem.h" #include "storage/pg_shmem.h"
...@@ -159,7 +159,6 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) ...@@ -159,7 +159,6 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
* Set up lock manager * Set up lock manager
*/ */
InitLocks(); InitLocks();
InitLockTable();
/* /*
* Set up process table * Set up process table
......
$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 LOCKING OVERVIEW
...@@ -151,7 +151,7 @@ tag - ...@@ -151,7 +151,7 @@ tag -
SHMEM offset of the LOCK object this PROCLOCK is for. SHMEM offset of the LOCK object this PROCLOCK is for.
tag.proc 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 - holdMask -
A bitmask for the lock types successfully acquired by this PROCLOCK. 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 ...@@ -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 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. 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
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * 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: * Interface:
* *
...@@ -930,7 +930,8 @@ DeadLockReport(void) ...@@ -930,7 +930,8 @@ DeadLockReport(void)
appendStringInfo(&buf, appendStringInfo(&buf,
_("Process %d waits for %s on %s; blocked by process %d."), _("Process %d waits for %s on %s; blocked by process %d."),
info->pid, info->pid,
GetLockmodeName(info->lockmode), GetLockmodeName(info->locktag.locktag_lockmethodid,
info->lockmode),
buf2.data, buf2.data,
nextpid); nextpid);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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,96 +18,12 @@ ...@@ -18,96 +18,12 @@
#include "access/subtrans.h" #include "access/subtrans.h"
#include "access/transam.h" #include "access/transam.h"
#include "access/xact.h" #include "access/xact.h"
#include "catalog/catalog.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/lmgr.h" #include "storage/lmgr.h"
#include "storage/procarray.h" #include "storage/procarray.h"
#include "utils/inval.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 * RelationInitLockInfo
* Initializes the lock information in a relation descriptor. * Initializes the lock information in a relation descriptor.
...@@ -141,8 +57,7 @@ LockRelation(Relation relation, LOCKMODE lockmode) ...@@ -141,8 +57,7 @@ LockRelation(Relation relation, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.dbId, relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId); relation->rd_lockInfo.lockRelId.relId);
res = LockAcquire(LockTableId, &tag, relation->rd_istemp, res = LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
lockmode, false, false);
/* /*
* Check to see if the relcache entry has been invalidated while we were * Check to see if the relcache entry has been invalidated while we were
...@@ -178,8 +93,7 @@ ConditionalLockRelation(Relation relation, LOCKMODE lockmode) ...@@ -178,8 +93,7 @@ ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.dbId, relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId); relation->rd_lockInfo.lockRelId.relId);
res = LockAcquire(LockTableId, &tag, relation->rd_istemp, res = LockAcquire(&tag, relation->rd_istemp, lockmode, false, true);
lockmode, false, true);
if (res == LOCKACQUIRE_NOT_AVAIL) if (res == LOCKACQUIRE_NOT_AVAIL)
return false; return false;
...@@ -213,7 +127,7 @@ UnlockRelation(Relation relation, LOCKMODE lockmode) ...@@ -213,7 +127,7 @@ UnlockRelation(Relation relation, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.dbId, relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId); 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) ...@@ -235,8 +149,7 @@ LockRelationForSession(LockRelId *relid, bool istemprel, LOCKMODE lockmode)
SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId); SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
(void) LockAcquire(LockTableId, &tag, istemprel, (void) LockAcquire(&tag, istemprel, lockmode, true, false);
lockmode, true, false);
} }
/* /*
...@@ -249,7 +162,7 @@ UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode) ...@@ -249,7 +162,7 @@ UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId); 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) ...@@ -271,8 +184,7 @@ LockRelationForExtension(Relation relation, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.dbId, relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId); relation->rd_lockInfo.lockRelId.relId);
(void) LockAcquire(LockTableId, &tag, relation->rd_istemp, (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
lockmode, false, false);
} }
/* /*
...@@ -287,7 +199,7 @@ UnlockRelationForExtension(Relation relation, LOCKMODE lockmode) ...@@ -287,7 +199,7 @@ UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.dbId, relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId); 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) ...@@ -306,8 +218,7 @@ LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.relId, relation->rd_lockInfo.lockRelId.relId,
blkno); blkno);
(void) LockAcquire(LockTableId, &tag, relation->rd_istemp, (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
lockmode, false, false);
} }
/* /*
...@@ -326,7 +237,7 @@ ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode) ...@@ -326,7 +237,7 @@ ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.relId, relation->rd_lockInfo.lockRelId.relId,
blkno); blkno);
return (LockAcquire(LockTableId, &tag, relation->rd_istemp, return (LockAcquire(&tag, relation->rd_istemp,
lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL); lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
} }
...@@ -343,7 +254,7 @@ UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode) ...@@ -343,7 +254,7 @@ UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
relation->rd_lockInfo.lockRelId.relId, relation->rd_lockInfo.lockRelId.relId,
blkno); blkno);
LockRelease(LockTableId, &tag, lockmode, false); LockRelease(&tag, lockmode, false);
} }
/* /*
...@@ -364,8 +275,7 @@ LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode) ...@@ -364,8 +275,7 @@ LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
ItemPointerGetBlockNumber(tid), ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid)); ItemPointerGetOffsetNumber(tid));
(void) LockAcquire(LockTableId, &tag, relation->rd_istemp, (void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
lockmode, false, false);
} }
/* /*
...@@ -385,7 +295,7 @@ ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode) ...@@ -385,7 +295,7 @@ ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
ItemPointerGetBlockNumber(tid), ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid)); ItemPointerGetOffsetNumber(tid));
return (LockAcquire(LockTableId, &tag, relation->rd_istemp, return (LockAcquire(&tag, relation->rd_istemp,
lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL); lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
} }
...@@ -403,7 +313,7 @@ UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode) ...@@ -403,7 +313,7 @@ UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
ItemPointerGetBlockNumber(tid), ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid)); ItemPointerGetOffsetNumber(tid));
LockRelease(LockTableId, &tag, lockmode, false); LockRelease(&tag, lockmode, false);
} }
/* /*
...@@ -420,8 +330,7 @@ XactLockTableInsert(TransactionId xid) ...@@ -420,8 +330,7 @@ XactLockTableInsert(TransactionId xid)
SET_LOCKTAG_TRANSACTION(tag, xid); SET_LOCKTAG_TRANSACTION(tag, xid);
(void) LockAcquire(LockTableId, &tag, false, (void) LockAcquire(&tag, false, ExclusiveLock, false, false);
ExclusiveLock, false, false);
} }
/* /*
...@@ -439,7 +348,7 @@ XactLockTableDelete(TransactionId xid) ...@@ -439,7 +348,7 @@ XactLockTableDelete(TransactionId xid)
SET_LOCKTAG_TRANSACTION(tag, xid); SET_LOCKTAG_TRANSACTION(tag, xid);
LockRelease(LockTableId, &tag, ExclusiveLock, false); LockRelease(&tag, ExclusiveLock, false);
} }
/* /*
...@@ -466,10 +375,9 @@ XactLockTableWait(TransactionId xid) ...@@ -466,10 +375,9 @@ XactLockTableWait(TransactionId xid)
SET_LOCKTAG_TRANSACTION(tag, xid); SET_LOCKTAG_TRANSACTION(tag, xid);
(void) LockAcquire(LockTableId, &tag, false, (void) LockAcquire(&tag, false, ShareLock, false, false);
ShareLock, false, false);
LockRelease(LockTableId, &tag, ShareLock, false); LockRelease(&tag, ShareLock, false);
if (!TransactionIdIsInProgress(xid)) if (!TransactionIdIsInProgress(xid))
break; break;
...@@ -502,11 +410,11 @@ ConditionalXactLockTableWait(TransactionId xid) ...@@ -502,11 +410,11 @@ ConditionalXactLockTableWait(TransactionId xid)
SET_LOCKTAG_TRANSACTION(tag, xid); SET_LOCKTAG_TRANSACTION(tag, xid);
if (LockAcquire(LockTableId, &tag, false, if (LockAcquire(&tag, false,
ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL) ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
return false; return false;
LockRelease(LockTableId, &tag, ShareLock, false); LockRelease(&tag, ShareLock, false);
if (!TransactionIdIsInProgress(xid)) if (!TransactionIdIsInProgress(xid))
break; break;
...@@ -545,8 +453,7 @@ LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, ...@@ -545,8 +453,7 @@ LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
objid, objid,
objsubid); objsubid);
(void) LockAcquire(LockTableId, &tag, false, (void) LockAcquire(&tag, false, lockmode, false, false);
lockmode, false, false);
} }
/* /*
...@@ -564,7 +471,7 @@ UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, ...@@ -564,7 +471,7 @@ UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
objid, objid,
objsubid); objsubid);
LockRelease(LockTableId, &tag, lockmode, false); LockRelease(&tag, lockmode, false);
} }
/* /*
...@@ -584,8 +491,7 @@ LockSharedObject(Oid classid, Oid objid, uint16 objsubid, ...@@ -584,8 +491,7 @@ LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
objid, objid,
objsubid); objsubid);
(void) LockAcquire(LockTableId, &tag, false, (void) LockAcquire(&tag, false, lockmode, false, false);
lockmode, false, false);
} }
/* /*
...@@ -603,5 +509,5 @@ UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid, ...@@ -603,5 +509,5 @@ UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
objid, objid,
objsubid); objsubid);
LockRelease(LockTableId, &tag, lockmode, false); LockRelease(&tag, lockmode, false);
} }
...@@ -8,11 +8,10 @@ ...@@ -8,11 +8,10 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Outside modules can create a lock table and acquire/release * A lock table is a shared memory hash table. When
* locks. A lock table is a shared memory hash table. When
* a process tries to acquire a lock of a type that conflicts * a process tries to acquire a lock of a type that conflicts
* with existing locks, it is put to sleep using the routines * with existing locks, it is put to sleep using the routines
* in storage/lmgr/proc.c. * in storage/lmgr/proc.c.
...@@ -22,8 +21,8 @@ ...@@ -22,8 +21,8 @@
* *
* Interface: * Interface:
* *
* LockAcquire(), LockRelease(), LockMethodTableInit(), * InitLocks(), GetLocksMethodTable(),
* LockMethodTableRename(), LockReleaseAll(), * LockAcquire(), LockRelease(), LockReleaseAll(),
* LockCheckConflicts(), GrantLock() * LockCheckConflicts(), GrantLock()
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
...@@ -50,31 +49,54 @@ int max_locks_per_xact; /* set by guc.c */ ...@@ -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)) 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 const LOCKMASK LockConflicts[] = {
static HTAB *LockMethodLockHash[MAX_LOCK_METHODS]; 0,
static HTAB *LockMethodProcLockHash[MAX_LOCK_METHODS];
static HTAB *LockMethodLocalHash[MAX_LOCK_METHODS];
/* exported so lmgr.c can initialize it */ /* AccessShareLock */
int NumLockMethods; (1 << AccessExclusiveLock),
/* RowShareLock */
(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
/* private state for GrantAwaitedLock */ /* RowExclusiveLock */
static LOCALLOCK *awaitedLock; (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
static ResourceOwner awaitedOwner; (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[] = static const char *const lock_mode_names[] =
{ {
"INVALID", "INVALID",
...@@ -88,6 +110,70 @@ static const char *const lock_mode_names[] = ...@@ -88,6 +110,70 @@ static const char *const lock_mode_names[] =
"AccessExclusiveLock" "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 #ifdef LOCK_DEBUG
...@@ -116,21 +202,20 @@ bool Debug_deadlocks = false; ...@@ -116,21 +202,20 @@ bool Debug_deadlocks = false;
inline static bool inline static bool
LOCK_DEBUG_ENABLED(const LOCK *lock) LOCK_DEBUG_ENABLED(const LOCKTAG *tag)
{ {
return return
(((Trace_locks && LOCK_LOCKMETHOD(*lock) == DEFAULT_LOCKMETHOD) (*(LockMethods[tag->locktag_lockmethodid]->trace_flag) &&
|| (Trace_userlocks && LOCK_LOCKMETHOD(*lock) == USER_LOCKMETHOD)) ((Oid) tag->locktag_field2 >= (Oid) Trace_lock_oidmin))
&& ((Oid) lock->tag.locktag_field2 >= (Oid) Trace_lock_oidmin)) || (Trace_lock_table &&
|| (Trace_lock_table (tag->locktag_field2 == Trace_lock_table));
&& (lock->tag.locktag_field2 == Trace_lock_table));
} }
inline static void inline static void
LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type) LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
{ {
if (LOCK_DEBUG_ENABLED(lock)) if (LOCK_DEBUG_ENABLED(&lock->tag))
elog(LOG, elog(LOG,
"%s: lock(%lx) id(%u,%u,%u,%u,%u,%u) grantMask(%x) " "%s: lock(%lx) id(%u,%u,%u,%u,%u,%u) grantMask(%x) "
"req(%d,%d,%d,%d,%d,%d,%d)=%d " "req(%d,%d,%d,%d,%d,%d,%d)=%d "
...@@ -146,14 +231,15 @@ LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type) ...@@ -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[1], lock->granted[2], lock->granted[3],
lock->granted[4], lock->granted[5], lock->granted[6], lock->granted[4], lock->granted[5], lock->granted[6],
lock->granted[7], lock->nGranted, lock->granted[7], lock->nGranted,
lock->waitProcs.size, lock_mode_names[type]); lock->waitProcs.size,
LockMethods[LOCK_LOCKMETHOD(*lock)]->lockModeNames[type]);
} }
inline static void inline static void
PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP) 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, elog(LOG,
"%s: proclock(%lx) lock(%lx) method(%u) proc(%lx) hold(%x)", "%s: proclock(%lx) lock(%lx) method(%u) proc(%lx) hold(%x)",
where, MAKE_OFFSET(proclockP), proclockP->tag.lock, where, MAKE_OFFSET(proclockP), proclockP->tag.lock,
...@@ -178,107 +264,21 @@ static void CleanUpLock(LOCKMETHODID lockmethodid, LOCK *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 void
InitLocks(void) InitLocks(void)
{ {
/* NOP */ char shmemName[64];
}
/*
* 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;
HASHCTL info; HASHCTL info;
int hash_flags; int hash_flags;
bool found;
long init_table_size, long init_table_size,
max_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 */ /* Compute init/max size to request for lock hashtables */
max_table_size = NLOCKENTS(); max_table_size = NLOCKENTS();
init_table_size = max_table_size / 2; 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 * allocate a hash table for LOCK structs. This is used to store
* per-locked-object information. * per-locked-object information.
...@@ -289,15 +289,15 @@ LockMethodTableInit(const char *tabName, ...@@ -289,15 +289,15 @@ LockMethodTableInit(const char *tabName,
info.hash = tag_hash; info.hash = tag_hash;
hash_flags = (HASH_ELEM | HASH_FUNCTION); hash_flags = (HASH_ELEM | HASH_FUNCTION);
sprintf(shmemName, "%s (lock hash)", tabName); sprintf(shmemName, "LOCK hash");
LockMethodLockHash[lockmethodid] = ShmemInitHash(shmemName, LockMethodLockHash = ShmemInitHash(shmemName,
init_table_size, init_table_size,
max_table_size, max_table_size,
&info, &info,
hash_flags); hash_flags);
if (!LockMethodLockHash[lockmethodid]) if (!LockMethodLockHash)
elog(FATAL, "could not initialize lock table \"%s\"", tabName); elog(FATAL, "could not initialize lock table \"%s\"", shmemName);
/* /*
* allocate a hash table for PROCLOCK structs. This is used to store * allocate a hash table for PROCLOCK structs. This is used to store
...@@ -308,15 +308,15 @@ LockMethodTableInit(const char *tabName, ...@@ -308,15 +308,15 @@ LockMethodTableInit(const char *tabName,
info.hash = tag_hash; info.hash = tag_hash;
hash_flags = (HASH_ELEM | HASH_FUNCTION); hash_flags = (HASH_ELEM | HASH_FUNCTION);
sprintf(shmemName, "%s (proclock hash)", tabName); sprintf(shmemName, "PROCLOCK hash");
LockMethodProcLockHash[lockmethodid] = ShmemInitHash(shmemName, LockMethodProcLockHash = ShmemInitHash(shmemName,
init_table_size, init_table_size,
max_table_size, max_table_size,
&info, &info,
hash_flags); hash_flags);
if (!LockMethodProcLockHash[lockmethodid]) if (!LockMethodProcLockHash)
elog(FATAL, "could not initialize lock table \"%s\"", tabName); elog(FATAL, "could not initialize lock table \"%s\"", shmemName);
/* /*
* allocate a non-shared hash table for LOCALLOCK structs. This is used * allocate a non-shared hash table for LOCALLOCK structs. This is used
...@@ -327,62 +327,39 @@ LockMethodTableInit(const char *tabName, ...@@ -327,62 +327,39 @@ LockMethodTableInit(const char *tabName,
* If so, delete and recreate it. (We could simply leave it, since it * 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.) * ought to be empty in the postmaster, but for safety let's zap it.)
*/ */
if (LockMethodLocalHash[lockmethodid]) if (LockMethodLocalHash)
hash_destroy(LockMethodLocalHash[lockmethodid]); hash_destroy(LockMethodLocalHash);
info.keysize = sizeof(LOCALLOCKTAG); info.keysize = sizeof(LOCALLOCKTAG);
info.entrysize = sizeof(LOCALLOCK); info.entrysize = sizeof(LOCALLOCK);
info.hash = tag_hash; info.hash = tag_hash;
hash_flags = (HASH_ELEM | HASH_FUNCTION); hash_flags = (HASH_ELEM | HASH_FUNCTION);
sprintf(shmemName, "%s (locallock hash)", tabName); LockMethodLocalHash = hash_create("LOCALLOCK hash",
LockMethodLocalHash[lockmethodid] = hash_create(shmemName,
128, 128,
&info, &info,
hash_flags); hash_flags);
pfree(shmemName);
return lockmethodid;
} }
/* /*
* LockMethodTableRename -- allocate another lockmethod ID to the same * Fetch the lock method table associated with a given lock
* 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.
*/ */
LockMethod
LOCKMETHODID GetLocksMethodTable(const LOCK *lock)
LockMethodTableRename(LOCKMETHODID lockmethodid)
{ {
LOCKMETHODID newLockMethodId; LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*lock);
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];
return newLockMethodId; Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
return LockMethods[lockmethodid];
} }
/* /*
* LockAcquire -- Check for lock conflicts, sleep if conflict found, * LockAcquire -- Check for lock conflicts, sleep if conflict found,
* set lock if/when no conflicts. * set lock if/when no conflicts.
* *
* Inputs: * Inputs:
* lockmethodid: identifies which lock table to use
* locktag: unique identifier for the lockable object * locktag: unique identifier for the lockable object
* isTempObject: is the lockable object a temporary object? (Under 2PC, * isTempObject: is the lockable object a temporary object? (Under 2PC,
* such locks cannot be persisted) * such locks cannot be persisted)
...@@ -403,43 +380,16 @@ LockMethodTableRename(LOCKMETHODID lockmethodid) ...@@ -403,43 +380,16 @@ LockMethodTableRename(LOCKMETHODID lockmethodid)
* *
* NOTE: if we wait for the lock, there is no way to abort the wait * NOTE: if we wait for the lock, there is no way to abort the wait
* short of aborting the transaction. * 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 LockAcquireResult
LockAcquire(LOCKMETHODID lockmethodid, LockAcquire(const LOCKTAG *locktag,
LOCKTAG *locktag,
bool isTempObject, bool isTempObject,
LOCKMODE lockmode, LOCKMODE lockmode,
bool sessionLock, bool sessionLock,
bool dontWait) bool dontWait)
{ {
LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
LockMethod lockMethodTable;
LOCALLOCKTAG localtag; LOCALLOCKTAG localtag;
LOCALLOCK *locallock; LOCALLOCK *locallock;
LOCK *lock; LOCK *lock;
...@@ -448,26 +398,23 @@ LockAcquire(LOCKMETHODID lockmethodid, ...@@ -448,26 +398,23 @@ LockAcquire(LOCKMETHODID lockmethodid,
bool found; bool found;
ResourceOwner owner; ResourceOwner owner;
LWLockId masterLock; LWLockId masterLock;
LockMethod lockMethodTable;
int status; 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 #ifdef LOCK_DEBUG
if (Trace_userlocks && lockmethodid == USER_LOCKMETHOD) if (LOCK_DEBUG_ENABLED(locktag))
elog(LOG, "LockAcquire: user lock [%u,%u] %s", elog(LOG, "LockAcquire: lock [%u,%u] %s",
locktag->locktag_field1, locktag->locktag_field2, locktag->locktag_field1, locktag->locktag_field2,
lock_mode_names[lockmode]); lockMethodTable->lockModeNames[lockmode]);
#endif #endif
/* ugly */ /* Session locks are never transactional, else check table */
locktag->locktag_lockmethodid = lockmethodid; if (!sessionLock && lockMethodTable->transactional)
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)
owner = CurrentResourceOwner; owner = CurrentResourceOwner;
else else
owner = NULL; owner = NULL;
...@@ -479,7 +426,7 @@ LockAcquire(LOCKMETHODID lockmethodid, ...@@ -479,7 +426,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
localtag.lock = *locktag; localtag.lock = *locktag;
localtag.mode = lockmode; localtag.mode = lockmode;
locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash[lockmethodid], locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
(void *) &localtag, (void *) &localtag,
HASH_ENTER, &found); HASH_ENTER, &found);
...@@ -527,7 +474,7 @@ LockAcquire(LOCKMETHODID lockmethodid, ...@@ -527,7 +474,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
/* /*
* Otherwise we've got to mess with the shared lock table. * Otherwise we've got to mess with the shared lock table.
*/ */
masterLock = lockMethodTable->masterLock; masterLock = LockMgrLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE); LWLockAcquire(masterLock, LW_EXCLUSIVE);
...@@ -539,7 +486,7 @@ LockAcquire(LOCKMETHODID lockmethodid, ...@@ -539,7 +486,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
* pointer is valid, since a lock object with no locks can go away * pointer is valid, since a lock object with no locks can go away
* anytime. * anytime.
*/ */
lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid], lock = (LOCK *) hash_search(LockMethodLockHash,
(void *) locktag, (void *) locktag,
HASH_ENTER_NULL, &found); HASH_ENTER_NULL, &found);
if (!lock) if (!lock)
...@@ -585,7 +532,7 @@ LockAcquire(LOCKMETHODID lockmethodid, ...@@ -585,7 +532,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
/* /*
* Find or create a proclock entry with this tag * Find or create a proclock entry with this tag
*/ */
proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid], proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
(void *) &proclocktag, (void *) &proclocktag,
HASH_ENTER_NULL, &found); HASH_ENTER_NULL, &found);
if (!proclock) if (!proclock)
...@@ -600,7 +547,7 @@ LockAcquire(LOCKMETHODID lockmethodid, ...@@ -600,7 +547,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
* anyone to release the lock object later. * anyone to release the lock object later.
*/ */
Assert(SHMQueueEmpty(&(lock->procLocks))); Assert(SHMQueueEmpty(&(lock->procLocks)));
if (!hash_search(LockMethodLockHash[lockmethodid], if (!hash_search(LockMethodLockHash,
(void *) &(lock->tag), (void *) &(lock->tag),
HASH_REMOVE, NULL)) HASH_REMOVE, NULL))
elog(PANIC, "lock table corrupted"); elog(PANIC, "lock table corrupted");
...@@ -657,7 +604,8 @@ LockAcquire(LOCKMETHODID lockmethodid, ...@@ -657,7 +604,8 @@ LockAcquire(LOCKMETHODID lockmethodid,
break; /* safe: we have a lock >= req level */ break; /* safe: we have a lock >= req level */
elog(LOG, "deadlock risk: raising lock level" elog(LOG, "deadlock risk: raising lock level"
" from %s to %s on object %u/%u/%u", " 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_field1, lock->tag.locktag_field2,
lock->tag.locktag_field3); lock->tag.locktag_field3);
break; break;
...@@ -682,7 +630,7 @@ LockAcquire(LOCKMETHODID lockmethodid, ...@@ -682,7 +630,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
*/ */
if (proclock->holdMask & LOCKBIT_ON(lockmode)) if (proclock->holdMask & LOCKBIT_ON(lockmode))
elog(ERROR, "lock %s on object %u/%u/%u is already held", 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_field1, lock->tag.locktag_field2,
lock->tag.locktag_field3); lock->tag.locktag_field3);
...@@ -718,7 +666,7 @@ LockAcquire(LOCKMETHODID lockmethodid, ...@@ -718,7 +666,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
{ {
SHMQueueDelete(&proclock->lockLink); SHMQueueDelete(&proclock->lockLink);
SHMQueueDelete(&proclock->procLink); SHMQueueDelete(&proclock->procLink);
if (!hash_search(LockMethodProcLockHash[lockmethodid], if (!hash_search(LockMethodProcLockHash,
(void *) &(proclock->tag), (void *) &(proclock->tag),
HASH_REMOVE, NULL)) HASH_REMOVE, NULL))
elog(PANIC, "proclock table corrupted"); elog(PANIC, "proclock table corrupted");
...@@ -779,11 +727,9 @@ LockAcquire(LOCKMETHODID lockmethodid, ...@@ -779,11 +727,9 @@ LockAcquire(LOCKMETHODID lockmethodid,
static void static void
RemoveLocalLock(LOCALLOCK *locallock) RemoveLocalLock(LOCALLOCK *locallock)
{ {
LOCKMETHODID lockmethodid = LOCALLOCK_LOCKMETHOD(*locallock);
pfree(locallock->lockOwners); pfree(locallock->lockOwners);
locallock->lockOwners = NULL; locallock->lockOwners = NULL;
if (!hash_search(LockMethodLocalHash[lockmethodid], if (!hash_search(LockMethodLocalHash,
(void *) &(locallock->tag), (void *) &(locallock->tag),
HASH_REMOVE, NULL)) HASH_REMOVE, NULL))
elog(WARNING, "locallock table corrupted"); elog(WARNING, "locallock table corrupted");
...@@ -964,7 +910,7 @@ CleanUpLock(LOCKMETHODID lockmethodid, LOCK *lock, PROCLOCK *proclock, ...@@ -964,7 +910,7 @@ CleanUpLock(LOCKMETHODID lockmethodid, LOCK *lock, PROCLOCK *proclock,
PROCLOCK_PRINT("CleanUpLock: deleting", proclock); PROCLOCK_PRINT("CleanUpLock: deleting", proclock);
SHMQueueDelete(&proclock->lockLink); SHMQueueDelete(&proclock->lockLink);
SHMQueueDelete(&proclock->procLink); SHMQueueDelete(&proclock->procLink);
if (!hash_search(LockMethodProcLockHash[lockmethodid], if (!hash_search(LockMethodProcLockHash,
(void *) &(proclock->tag), (void *) &(proclock->tag),
HASH_REMOVE, NULL)) HASH_REMOVE, NULL))
elog(PANIC, "proclock table corrupted"); elog(PANIC, "proclock table corrupted");
...@@ -978,7 +924,7 @@ CleanUpLock(LOCKMETHODID lockmethodid, LOCK *lock, PROCLOCK *proclock, ...@@ -978,7 +924,7 @@ CleanUpLock(LOCKMETHODID lockmethodid, LOCK *lock, PROCLOCK *proclock,
*/ */
LOCK_PRINT("CleanUpLock: deleting", lock, 0); LOCK_PRINT("CleanUpLock: deleting", lock, 0);
Assert(SHMQueueEmpty(&(lock->procLocks))); Assert(SHMQueueEmpty(&(lock->procLocks)));
if (!hash_search(LockMethodLockHash[lockmethodid], if (!hash_search(LockMethodLockHash,
(void *) &(lock->tag), (void *) &(lock->tag),
HASH_REMOVE, NULL)) HASH_REMOVE, NULL))
elog(PANIC, "lock table corrupted"); elog(PANIC, "lock table corrupted");
...@@ -1053,8 +999,6 @@ WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock, ...@@ -1053,8 +999,6 @@ WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,
char *new_status; char *new_status;
int len; int len;
Assert(lockmethodid < NumLockMethods);
LOCK_PRINT("WaitOnLock: sleeping on lock", LOCK_PRINT("WaitOnLock: sleeping on lock",
locallock->lock, locallock->tag.mode); locallock->lock, locallock->tag.mode);
...@@ -1092,7 +1036,7 @@ WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock, ...@@ -1092,7 +1036,7 @@ WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,
awaitedLock = NULL; awaitedLock = NULL;
LOCK_PRINT("WaitOnLock: aborting on lock", LOCK_PRINT("WaitOnLock: aborting on lock",
locallock->lock, locallock->tag.mode); locallock->lock, locallock->tag.mode);
LWLockRelease(lockMethodTable->masterLock); LWLockRelease(LockMgrLock);
/* /*
* Now that we aren't holding the LockMgrLock, we can give an error * Now that we aren't holding the LockMgrLock, we can give an error
...@@ -1131,7 +1075,7 @@ RemoveFromWaitQueue(PGPROC *proc) ...@@ -1131,7 +1075,7 @@ RemoveFromWaitQueue(PGPROC *proc)
Assert(proc->links.next != INVALID_OFFSET); Assert(proc->links.next != INVALID_OFFSET);
Assert(waitLock); Assert(waitLock);
Assert(waitLock->waitProcs.size > 0); Assert(waitLock->waitProcs.size > 0);
Assert(0 < lockmethodid && lockmethodid < NumLockMethods); Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
/* Remove proc from lock's wait queue */ /* Remove proc from lock's wait queue */
SHMQueueDelete(&(proc->links)); SHMQueueDelete(&(proc->links));
...@@ -1162,9 +1106,9 @@ RemoveFromWaitQueue(PGPROC *proc) ...@@ -1162,9 +1106,9 @@ RemoveFromWaitQueue(PGPROC *proc)
} }
/* /*
* LockRelease -- look up 'locktag' in lock table 'lockmethodid' and * LockRelease -- look up 'locktag' and release one 'lockmode' lock on it.
* release one 'lockmode' lock on it. Release a session lock if * Release a session lock if 'sessionLock' is true, else release a
* 'sessionLock' is true, else release a regular transaction lock. * regular transaction lock.
* *
* Side Effects: find any waiting processes that are now wakable, * Side Effects: find any waiting processes that are now wakable,
* grant them their requested locks and awaken them. * grant them their requested locks and awaken them.
...@@ -1173,32 +1117,30 @@ RemoveFromWaitQueue(PGPROC *proc) ...@@ -1173,32 +1117,30 @@ RemoveFromWaitQueue(PGPROC *proc)
* come along and request the lock.) * come along and request the lock.)
*/ */
bool bool
LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
LOCKMODE lockmode, bool sessionLock)
{ {
LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
LockMethod lockMethodTable;
LOCALLOCKTAG localtag; LOCALLOCKTAG localtag;
LOCALLOCK *locallock; LOCALLOCK *locallock;
LOCK *lock; LOCK *lock;
PROCLOCK *proclock; PROCLOCK *proclock;
LWLockId masterLock; LWLockId masterLock;
LockMethod lockMethodTable;
bool wakeupNeeded; 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 #ifdef LOCK_DEBUG
if (Trace_userlocks && lockmethodid == USER_LOCKMETHOD) if (LOCK_DEBUG_ENABLED(locktag))
elog(LOG, "LockRelease: user lock [%u,%u] %s", elog(LOG, "LockRelease: lock [%u,%u] %s",
locktag->locktag_field1, locktag->locktag_field2, locktag->locktag_field1, locktag->locktag_field2,
lock_mode_names[lockmode]); lockMethodTable->lockModeNames[lockmode]);
#endif #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 * Find the LOCALLOCK entry for this lock and lockmode
*/ */
...@@ -1206,7 +1148,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -1206,7 +1148,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
localtag.lock = *locktag; localtag.lock = *locktag;
localtag.mode = lockmode; localtag.mode = lockmode;
locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash[lockmethodid], locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
(void *) &localtag, (void *) &localtag,
HASH_FIND, NULL); HASH_FIND, NULL);
...@@ -1216,7 +1158,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -1216,7 +1158,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
if (!locallock || locallock->nLocks <= 0) if (!locallock || locallock->nLocks <= 0)
{ {
elog(WARNING, "you don't own a lock of type %s", elog(WARNING, "you don't own a lock of type %s",
lock_mode_names[lockmode]); lockMethodTable->lockModeNames[lockmode]);
return FALSE; return FALSE;
} }
...@@ -1228,8 +1170,8 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -1228,8 +1170,8 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
ResourceOwner owner; ResourceOwner owner;
int i; int i;
/* Session locks and user locks are not transactional */ /* Session locks are never transactional, else check table */
if (!sessionLock && lockmethodid == DEFAULT_LOCKMETHOD) if (!sessionLock && lockMethodTable->transactional)
owner = CurrentResourceOwner; owner = CurrentResourceOwner;
else else
owner = NULL; owner = NULL;
...@@ -1253,7 +1195,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -1253,7 +1195,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
{ {
/* don't release a lock belonging to another owner */ /* don't release a lock belonging to another owner */
elog(WARNING, "you don't own a lock of type %s", elog(WARNING, "you don't own a lock of type %s",
lock_mode_names[lockmode]); lockMethodTable->lockModeNames[lockmode]);
return FALSE; return FALSE;
} }
} }
...@@ -1270,7 +1212,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -1270,7 +1212,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
/* /*
* Otherwise we've got to mess with the shared lock table. * Otherwise we've got to mess with the shared lock table.
*/ */
masterLock = lockMethodTable->masterLock; masterLock = LockMgrLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE); LWLockAcquire(masterLock, LW_EXCLUSIVE);
...@@ -1293,7 +1235,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, ...@@ -1293,7 +1235,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
PROCLOCK_PRINT("LockRelease: WRONGTYPE", proclock); PROCLOCK_PRINT("LockRelease: WRONGTYPE", proclock);
LWLockRelease(masterLock); LWLockRelease(masterLock);
elog(WARNING, "you don't own a lock of type %s", elog(WARNING, "you don't own a lock of type %s",
lock_mode_names[lockmode]); lockMethodTable->lockModeNames[lockmode]);
RemoveLocalLock(locallock); RemoveLocalLock(locallock);
return FALSE; return FALSE;
} }
...@@ -1332,18 +1274,17 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks) ...@@ -1332,18 +1274,17 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
PROCLOCK *proclock; PROCLOCK *proclock;
LOCK *lock; LOCK *lock;
if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
elog(ERROR, "unrecognized lock method: %d", lockmethodid);
lockMethodTable = LockMethods[lockmethodid];
#ifdef LOCK_DEBUG #ifdef LOCK_DEBUG
if (lockmethodid == USER_LOCKMETHOD ? Trace_userlocks : Trace_locks) if (*(lockMethodTable->trace_flag))
elog(LOG, "LockReleaseAll: lockmethod=%d", lockmethodid); elog(LOG, "LockReleaseAll: lockmethod=%d", lockmethodid);
#endif #endif
Assert(lockmethodid < NumLockMethods);
lockMethodTable = LockMethods[lockmethodid];
if (!lockMethodTable)
elog(ERROR, "unrecognized lock method: %d", lockmethodid);
numLockModes = lockMethodTable->numLockModes; numLockModes = lockMethodTable->numLockModes;
masterLock = lockMethodTable->masterLock; masterLock = LockMgrLock;
/* /*
* First we run through the locallock table and get rid of unwanted * First we run through the locallock table and get rid of unwanted
...@@ -1352,7 +1293,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks) ...@@ -1352,7 +1293,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
* pointing to the same proclock, and we daren't end up with any dangling * pointing to the same proclock, and we daren't end up with any dangling
* pointers. * pointers.
*/ */
hash_seq_init(&status, LockMethodLocalHash[lockmethodid]); hash_seq_init(&status, LockMethodLocalHash);
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL) while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
{ {
...@@ -1480,7 +1421,7 @@ next_item: ...@@ -1480,7 +1421,7 @@ next_item:
LWLockRelease(masterLock); LWLockRelease(masterLock);
#ifdef LOCK_DEBUG #ifdef LOCK_DEBUG
if (lockmethodid == USER_LOCKMETHOD ? Trace_userlocks : Trace_locks) if (*(lockMethodTable->trace_flag))
elog(LOG, "LockReleaseAll done"); elog(LOG, "LockReleaseAll done");
#endif #endif
} }
...@@ -1488,8 +1429,6 @@ next_item: ...@@ -1488,8 +1429,6 @@ next_item:
/* /*
* LockReleaseCurrentOwner * LockReleaseCurrentOwner
* Release all locks belonging to CurrentResourceOwner * Release all locks belonging to CurrentResourceOwner
*
* Only DEFAULT_LOCKMETHOD locks can belong to a resource owner.
*/ */
void void
LockReleaseCurrentOwner(void) LockReleaseCurrentOwner(void)
...@@ -1499,12 +1438,12 @@ LockReleaseCurrentOwner(void) ...@@ -1499,12 +1438,12 @@ LockReleaseCurrentOwner(void)
LOCALLOCKOWNER *lockOwners; LOCALLOCKOWNER *lockOwners;
int i; int i;
hash_seq_init(&status, LockMethodLocalHash[DEFAULT_LOCKMETHOD]); hash_seq_init(&status, LockMethodLocalHash);
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL) while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
{ {
/* Ignore items that must be nontransactional */ /* Ignore items that must be nontransactional */
if (LOCALLOCK_LOCKMETHOD(*locallock) != DEFAULT_LOCKMETHOD) if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue; continue;
/* Scan to see if there are any locks belonging to current owner */ /* Scan to see if there are any locks belonging to current owner */
...@@ -1532,8 +1471,7 @@ LockReleaseCurrentOwner(void) ...@@ -1532,8 +1471,7 @@ LockReleaseCurrentOwner(void)
/* We want to call LockRelease just once */ /* We want to call LockRelease just once */
lockOwners[i].nLocks = 1; lockOwners[i].nLocks = 1;
locallock->nLocks = 1; locallock->nLocks = 1;
if (!LockRelease(DEFAULT_LOCKMETHOD, if (!LockRelease(&locallock->tag.lock,
&locallock->tag.lock,
locallock->tag.mode, locallock->tag.mode,
false)) false))
elog(WARNING, "LockReleaseCurrentOwner: failed??"); elog(WARNING, "LockReleaseCurrentOwner: failed??");
...@@ -1559,7 +1497,7 @@ LockReassignCurrentOwner(void) ...@@ -1559,7 +1497,7 @@ LockReassignCurrentOwner(void)
Assert(parent != NULL); Assert(parent != NULL);
hash_seq_init(&status, LockMethodLocalHash[DEFAULT_LOCKMETHOD]); hash_seq_init(&status, LockMethodLocalHash);
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL) while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
{ {
...@@ -1568,7 +1506,7 @@ LockReassignCurrentOwner(void) ...@@ -1568,7 +1506,7 @@ LockReassignCurrentOwner(void)
int ip = -1; int ip = -1;
/* Ignore items that must be nontransactional */ /* Ignore items that must be nontransactional */
if (LOCALLOCK_LOCKMETHOD(*locallock) != DEFAULT_LOCKMETHOD) if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue; continue;
/* /*
...@@ -1610,7 +1548,7 @@ LockReassignCurrentOwner(void) ...@@ -1610,7 +1548,7 @@ LockReassignCurrentOwner(void)
* Do the preparatory work for a PREPARE: make 2PC state file records * Do the preparatory work for a PREPARE: make 2PC state file records
* for all locks currently held. * 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 * 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 * any session locks (should be OK since only VACUUM uses those) and we
...@@ -1621,7 +1559,6 @@ LockReassignCurrentOwner(void) ...@@ -1621,7 +1559,6 @@ LockReassignCurrentOwner(void)
void void
AtPrepare_Locks(void) AtPrepare_Locks(void)
{ {
LOCKMETHODID lockmethodid = DEFAULT_LOCKMETHOD;
HASH_SEQ_STATUS status; HASH_SEQ_STATUS status;
LOCALLOCK *locallock; LOCALLOCK *locallock;
...@@ -1629,7 +1566,7 @@ AtPrepare_Locks(void) ...@@ -1629,7 +1566,7 @@ AtPrepare_Locks(void)
* We don't need to touch shared memory for this --- all the necessary * We don't need to touch shared memory for this --- all the necessary
* state information is in the locallock table. * 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) while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
{ {
...@@ -1637,8 +1574,8 @@ AtPrepare_Locks(void) ...@@ -1637,8 +1574,8 @@ AtPrepare_Locks(void)
LOCALLOCKOWNER *lockOwners = locallock->lockOwners; LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
int i; int i;
/* Ignore items that are not of the lockmethod to be processed */ /* Ignore nontransactional locks */
if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid) if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue; continue;
/* Ignore it if we don't actually hold the lock */ /* Ignore it if we don't actually hold the lock */
...@@ -1689,12 +1626,9 @@ void ...@@ -1689,12 +1626,9 @@ void
PostPrepare_Locks(TransactionId xid) PostPrepare_Locks(TransactionId xid)
{ {
PGPROC *newproc = TwoPhaseGetDummyProc(xid); PGPROC *newproc = TwoPhaseGetDummyProc(xid);
LOCKMETHODID lockmethodid = DEFAULT_LOCKMETHOD;
HASH_SEQ_STATUS status; HASH_SEQ_STATUS status;
SHM_QUEUE *procLocks = &(MyProc->procLocks); SHM_QUEUE *procLocks = &(MyProc->procLocks);
LWLockId masterLock; LWLockId masterLock;
LockMethod lockMethodTable;
int numLockModes;
LOCALLOCK *locallock; LOCALLOCK *locallock;
PROCLOCK *proclock; PROCLOCK *proclock;
PROCLOCKTAG proclocktag; PROCLOCKTAG proclocktag;
...@@ -1704,12 +1638,7 @@ PostPrepare_Locks(TransactionId xid) ...@@ -1704,12 +1638,7 @@ PostPrepare_Locks(TransactionId xid)
/* This is a critical section: any error means big trouble */ /* This is a critical section: any error means big trouble */
START_CRIT_SECTION(); START_CRIT_SECTION();
lockMethodTable = LockMethods[lockmethodid]; masterLock = LockMgrLock;
if (!lockMethodTable)
elog(ERROR, "unrecognized lock method: %d", lockmethodid);
numLockModes = lockMethodTable->numLockModes;
masterLock = lockMethodTable->masterLock;
/* /*
* First we run through the locallock table and get rid of unwanted * First we run through the locallock table and get rid of unwanted
...@@ -1720,7 +1649,7 @@ PostPrepare_Locks(TransactionId xid) ...@@ -1720,7 +1649,7 @@ PostPrepare_Locks(TransactionId xid)
* pointing to the same proclock, and we daren't end up with any dangling * pointing to the same proclock, and we daren't end up with any dangling
* pointers. * pointers.
*/ */
hash_seq_init(&status, LockMethodLocalHash[lockmethodid]); hash_seq_init(&status, LockMethodLocalHash);
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL) while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
{ {
...@@ -1735,8 +1664,8 @@ PostPrepare_Locks(TransactionId xid) ...@@ -1735,8 +1664,8 @@ PostPrepare_Locks(TransactionId xid)
continue; continue;
} }
/* Ignore items that are not of the lockmethod to be removed */ /* Ignore nontransactional locks */
if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid) if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue; continue;
/* We already checked there are no session locks */ /* We already checked there are no session locks */
...@@ -1768,8 +1697,8 @@ PostPrepare_Locks(TransactionId xid) ...@@ -1768,8 +1697,8 @@ PostPrepare_Locks(TransactionId xid)
lock = (LOCK *) MAKE_PTR(proclock->tag.lock); lock = (LOCK *) MAKE_PTR(proclock->tag.lock);
/* Ignore items that are not of the lockmethod to be removed */ /* Ignore nontransactional locks */
if (LOCK_LOCKMETHOD(*lock) != lockmethodid) if (!LockMethods[LOCK_LOCKMETHOD(*lock)]->transactional)
goto next_item; goto next_item;
PROCLOCK_PRINT("PostPrepare_Locks", proclock); PROCLOCK_PRINT("PostPrepare_Locks", proclock);
...@@ -1798,7 +1727,7 @@ PostPrepare_Locks(TransactionId xid) ...@@ -1798,7 +1727,7 @@ PostPrepare_Locks(TransactionId xid)
*/ */
SHMQueueDelete(&proclock->lockLink); SHMQueueDelete(&proclock->lockLink);
SHMQueueDelete(&proclock->procLink); SHMQueueDelete(&proclock->procLink);
if (!hash_search(LockMethodProcLockHash[lockmethodid], if (!hash_search(LockMethodProcLockHash,
(void *) &(proclock->tag), (void *) &(proclock->tag),
HASH_REMOVE, NULL)) HASH_REMOVE, NULL))
elog(PANIC, "proclock table corrupted"); elog(PANIC, "proclock table corrupted");
...@@ -1810,7 +1739,7 @@ PostPrepare_Locks(TransactionId xid) ...@@ -1810,7 +1739,7 @@ PostPrepare_Locks(TransactionId xid)
proclocktag.lock = MAKE_OFFSET(lock); proclocktag.lock = MAKE_OFFSET(lock);
proclocktag.proc = MAKE_OFFSET(newproc); proclocktag.proc = MAKE_OFFSET(newproc);
newproclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid], newproclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
(void *) &proclocktag, (void *) &proclocktag,
HASH_ENTER_NULL, &found); HASH_ENTER_NULL, &found);
if (!newproclock) if (!newproclock)
...@@ -1859,12 +1788,9 @@ next_item: ...@@ -1859,12 +1788,9 @@ next_item:
Size Size
LockShmemSize(void) LockShmemSize(void)
{ {
Size size; Size size = 0;
long max_table_size = NLOCKENTS(); long max_table_size = NLOCKENTS();
/* lock method headers */
size = MAX_LOCK_METHODS * MAXALIGN(sizeof(LockMethodData));
/* lockHash table */ /* lockHash table */
size = add_size(size, hash_estimate_size(max_table_size, sizeof(LOCK))); size = add_size(size, hash_estimate_size(max_table_size, sizeof(LOCK)));
...@@ -1910,7 +1836,7 @@ GetLockStatusData(void) ...@@ -1910,7 +1836,7 @@ GetLockStatusData(void)
LWLockAcquire(LockMgrLock, LW_EXCLUSIVE); LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
proclockTable = LockMethodProcLockHash[DEFAULT_LOCKMETHOD]; proclockTable = LockMethodProcLockHash;
data->nelements = i = proclockTable->hctl->nentries; data->nelements = i = proclockTable->hctl->nentries;
...@@ -1944,17 +1870,18 @@ GetLockStatusData(void) ...@@ -1944,17 +1870,18 @@ GetLockStatusData(void)
/* Provide the textual name of any lock mode */ /* Provide the textual name of any lock mode */
const char * const char *
GetLockmodeName(LOCKMODE mode) GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
{ {
Assert(mode <= MAX_LOCKMODES); Assert(lockmethodid > 0 && lockmethodid < lengthof(LockMethods));
return lock_mode_names[mode]; Assert(mode > 0 && mode <= LockMethods[lockmethodid]->numLockModes);
return LockMethods[lockmethodid]->lockModeNames[mode];
} }
#ifdef LOCK_DEBUG #ifdef LOCK_DEBUG
/* /*
* Dump all locks in the given proc's procLocks list. * 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 void
DumpLocks(PGPROC *proc) DumpLocks(PGPROC *proc)
...@@ -1962,19 +1889,12 @@ DumpLocks(PGPROC *proc) ...@@ -1962,19 +1889,12 @@ DumpLocks(PGPROC *proc)
SHM_QUEUE *procLocks; SHM_QUEUE *procLocks;
PROCLOCK *proclock; PROCLOCK *proclock;
LOCK *lock; LOCK *lock;
int lockmethodid = DEFAULT_LOCKMETHOD;
LockMethod lockMethodTable;
if (proc == NULL) if (proc == NULL)
return; return;
procLocks = &proc->procLocks; procLocks = &proc->procLocks;
Assert(lockmethodid < NumLockMethods);
lockMethodTable = LockMethods[lockmethodid];
if (!lockMethodTable)
return;
if (proc->waitLock) if (proc->waitLock)
LOCK_PRINT("DumpLocks: waiting on", proc->waitLock, 0); LOCK_PRINT("DumpLocks: waiting on", proc->waitLock, 0);
...@@ -1996,7 +1916,9 @@ DumpLocks(PGPROC *proc) ...@@ -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 void
DumpAllLocks(void) DumpAllLocks(void)
...@@ -2004,23 +1926,13 @@ DumpAllLocks(void) ...@@ -2004,23 +1926,13 @@ DumpAllLocks(void)
PGPROC *proc; PGPROC *proc;
PROCLOCK *proclock; PROCLOCK *proclock;
LOCK *lock; LOCK *lock;
int lockmethodid = DEFAULT_LOCKMETHOD;
LockMethod lockMethodTable;
HTAB *proclockTable; HTAB *proclockTable;
HASH_SEQ_STATUS status; HASH_SEQ_STATUS status;
proc = MyProc; proc = MyProc;
if (proc == NULL) proclockTable = LockMethodProcLockHash;
return;
Assert(lockmethodid < NumLockMethods);
lockMethodTable = LockMethods[lockmethodid];
if (!lockMethodTable)
return;
proclockTable = LockMethodProcLockHash[lockmethodid];
if (proc->waitLock) if (proc && proc->waitLock)
LOCK_PRINT("DumpAllLocks: waiting on", proc->waitLock, 0); LOCK_PRINT("DumpAllLocks: waiting on", proc->waitLock, 0);
hash_seq_init(&status, proclockTable); hash_seq_init(&status, proclockTable);
...@@ -2071,19 +1983,18 @@ lock_twophase_recover(TransactionId xid, uint16 info, ...@@ -2071,19 +1983,18 @@ lock_twophase_recover(TransactionId xid, uint16 info,
lockmode = rec->lockmode; lockmode = rec->lockmode;
lockmethodid = locktag->locktag_lockmethodid; lockmethodid = locktag->locktag_lockmethodid;
Assert(lockmethodid < NumLockMethods); if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
lockMethodTable = LockMethods[lockmethodid];
if (!lockMethodTable)
elog(ERROR, "unrecognized lock method: %d", lockmethodid); elog(ERROR, "unrecognized lock method: %d", lockmethodid);
lockMethodTable = LockMethods[lockmethodid];
masterLock = lockMethodTable->masterLock; masterLock = LockMgrLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE); LWLockAcquire(masterLock, LW_EXCLUSIVE);
/* /*
* Find or create a lock with this tag. * Find or create a lock with this tag.
*/ */
lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid], lock = (LOCK *) hash_search(LockMethodLockHash,
(void *) locktag, (void *) locktag,
HASH_ENTER_NULL, &found); HASH_ENTER_NULL, &found);
if (!lock) if (!lock)
...@@ -2128,7 +2039,7 @@ lock_twophase_recover(TransactionId xid, uint16 info, ...@@ -2128,7 +2039,7 @@ lock_twophase_recover(TransactionId xid, uint16 info,
/* /*
* Find or create a proclock entry with this tag * Find or create a proclock entry with this tag
*/ */
proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid], proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
(void *) &proclocktag, (void *) &proclocktag,
HASH_ENTER_NULL, &found); HASH_ENTER_NULL, &found);
if (!proclock) if (!proclock)
...@@ -2143,7 +2054,7 @@ lock_twophase_recover(TransactionId xid, uint16 info, ...@@ -2143,7 +2054,7 @@ lock_twophase_recover(TransactionId xid, uint16 info,
* anyone to release the lock object later. * anyone to release the lock object later.
*/ */
Assert(SHMQueueEmpty(&(lock->procLocks))); Assert(SHMQueueEmpty(&(lock->procLocks)));
if (!hash_search(LockMethodLockHash[lockmethodid], if (!hash_search(LockMethodLockHash,
(void *) &(lock->tag), (void *) &(lock->tag),
HASH_REMOVE, NULL)) HASH_REMOVE, NULL))
elog(PANIC, "lock table corrupted"); elog(PANIC, "lock table corrupted");
...@@ -2186,7 +2097,7 @@ lock_twophase_recover(TransactionId xid, uint16 info, ...@@ -2186,7 +2097,7 @@ lock_twophase_recover(TransactionId xid, uint16 info,
*/ */
if (proclock->holdMask & LOCKBIT_ON(lockmode)) if (proclock->holdMask & LOCKBIT_ON(lockmode))
elog(ERROR, "lock %s on object %u/%u/%u is already held", 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_field1, lock->tag.locktag_field2,
lock->tag.locktag_field3); lock->tag.locktag_field3);
...@@ -2224,19 +2135,18 @@ lock_twophase_postcommit(TransactionId xid, uint16 info, ...@@ -2224,19 +2135,18 @@ lock_twophase_postcommit(TransactionId xid, uint16 info,
lockmode = rec->lockmode; lockmode = rec->lockmode;
lockmethodid = locktag->locktag_lockmethodid; lockmethodid = locktag->locktag_lockmethodid;
Assert(lockmethodid < NumLockMethods); if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
lockMethodTable = LockMethods[lockmethodid];
if (!lockMethodTable)
elog(ERROR, "unrecognized lock method: %d", lockmethodid); elog(ERROR, "unrecognized lock method: %d", lockmethodid);
lockMethodTable = LockMethods[lockmethodid];
masterLock = lockMethodTable->masterLock; masterLock = LockMgrLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE); LWLockAcquire(masterLock, LW_EXCLUSIVE);
/* /*
* Re-find the lock object (it had better be there). * Re-find the lock object (it had better be there).
*/ */
lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid], lock = (LOCK *) hash_search(LockMethodLockHash,
(void *) locktag, (void *) locktag,
HASH_FIND, NULL); HASH_FIND, NULL);
if (!lock) if (!lock)
...@@ -2248,7 +2158,7 @@ lock_twophase_postcommit(TransactionId xid, uint16 info, ...@@ -2248,7 +2158,7 @@ lock_twophase_postcommit(TransactionId xid, uint16 info,
MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG)); /* must clear padding */ MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG)); /* must clear padding */
proclocktag.lock = MAKE_OFFSET(lock); proclocktag.lock = MAKE_OFFSET(lock);
proclocktag.proc = MAKE_OFFSET(proc); proclocktag.proc = MAKE_OFFSET(proc);
proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid], proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
(void *) &proclocktag, (void *) &proclocktag,
HASH_FIND, NULL); HASH_FIND, NULL);
if (!proclock) if (!proclock)
...@@ -2263,7 +2173,7 @@ lock_twophase_postcommit(TransactionId xid, uint16 info, ...@@ -2263,7 +2173,7 @@ lock_twophase_postcommit(TransactionId xid, uint16 info,
PROCLOCK_PRINT("lock_twophase_postcommit: WRONGTYPE", proclock); PROCLOCK_PRINT("lock_twophase_postcommit: WRONGTYPE", proclock);
LWLockRelease(masterLock); LWLockRelease(masterLock);
elog(WARNING, "you don't own a lock of type %s", elog(WARNING, "you don't own a lock of type %s",
lock_mode_names[lockmode]); lockMethodTable->lockModeNames[lockmode]);
return; return;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -630,7 +630,7 @@ ProcSleep(LockMethod lockMethodTable,
LOCK *lock, LOCK *lock,
PROCLOCK *proclock) PROCLOCK *proclock)
{ {
LWLockId masterLock = lockMethodTable->masterLock; LWLockId masterLock = LockMgrLock;
PROC_QUEUE *waitQueue = &(lock->waitProcs); PROC_QUEUE *waitQueue = &(lock->waitProcs);
LOCKMASK myHeldLocks = MyProc->heldLocks; LOCKMASK myHeldLocks = MyProc->heldLocks;
bool early_deadlock = false; bool early_deadlock = false;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Copyright (c) 2002-2005, PostgreSQL Global Development Group * Copyright (c) 2002-2005, PostgreSQL Global Development Group
* *
* IDENTIFICATION * 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) ...@@ -256,7 +256,8 @@ pg_lock_status(PG_FUNCTION_ARGS)
else else
nulls[10] = 'n'; nulls[10] = 'n';
values[11] = DirectFunctionCall1(textin, values[11] = DirectFunctionCall1(textin,
CStringGetDatum(GetLockmodeName(mode))); CStringGetDatum(GetLockmodeName(LOCK_LOCKMETHOD(*lock),
mode)));
values[12] = BoolGetDatum(granted); values[12] = BoolGetDatum(granted);
tuple = heap_formtuple(funcctx->tuple_desc, values, nulls); tuple = heap_formtuple(funcctx->tuple_desc, values, nulls);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -3362,7 +3362,7 @@ RelationIdIsInInitFile(Oid relationId)
* just after sending them. The unlink before ensures that a backend that's * 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 * 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 * 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 * 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 * 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, * that we've just rendered invalid. Such a backend will see the SI messages,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -18,29 +18,6 @@
#include "utils/rel.h" #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); extern void RelationInitLockInfo(Relation relation);
/* Lock a relation */ /* Lock a relation */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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; ...@@ -55,50 +55,68 @@ typedef int LOCKMODE;
#define LOCKBIT_ON(lockmode) (1 << (lockmode)) #define LOCKBIT_ON(lockmode) (1 << (lockmode))
#define LOCKBIT_OFF(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 * This data structure defines the locking semantics associated with a
* memory. Currently, none of these fields change after startup. In addition * "lock method". The semantics specify the meaning of each lock mode
* to the LockMethodData, a lock table has a shared "lockHash" table holding * (by defining which lock modes it conflicts with), and also whether locks
* per-locked-object lock information, and a shared "proclockHash" table * of this method are transactional (ie, are released at transaction end).
* holding per-lock-holder/waiter lock information. * 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 * transactional -- TRUE if locks are released automatically at xact end.
* are defined on this lock table
* *
* conflictTab -- this is an array of bitmasks showing lock * conflictTab -- this is an array of bitmasks showing lock
* type conflicts. conflictTab[i] is a mask with the j-th bit * mode conflicts. conflictTab[i] is a mask with the j-th bit
* turned on if lock types i and j conflict. * 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 typedef struct LockMethodData
{ {
LWLockId masterLock;
int numLockModes; int numLockModes;
LOCKMASK conflictTab[MAX_LOCKMODES]; bool transactional;
const LOCKMASK *conflictTab;
const char * const *lockModeNames;
const bool *trace_flag;
} LockMethodData; } 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 ...@@ -138,9 +156,7 @@ typedef enum LockTagType
* to widen Oid, BlockNumber, or TransactionId to more than 32 bits. * to widen Oid, BlockNumber, or TransactionId to more than 32 bits.
* *
* We include lockmethodid in the locktag so that a single hash table in * We include lockmethodid in the locktag so that a single hash table in
* shared memory can store locks of different lockmethods. For largely * shared memory can store locks of different lockmethods.
* historical reasons, it's passed to the lock.c routines as a separate
* argument and then stored into the locktag.
*/ */
typedef struct LOCKTAG typedef struct LOCKTAG
{ {
...@@ -162,42 +178,48 @@ typedef struct LOCKTAG ...@@ -162,42 +178,48 @@ typedef struct LOCKTAG
(locktag).locktag_field2 = (reloid), \ (locktag).locktag_field2 = (reloid), \
(locktag).locktag_field3 = 0, \ (locktag).locktag_field3 = 0, \
(locktag).locktag_field4 = 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) \ #define SET_LOCKTAG_RELATION_EXTEND(locktag,dboid,reloid) \
((locktag).locktag_field1 = (dboid), \ ((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (reloid), \ (locktag).locktag_field2 = (reloid), \
(locktag).locktag_field3 = 0, \ (locktag).locktag_field3 = 0, \
(locktag).locktag_field4 = 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) \ #define SET_LOCKTAG_PAGE(locktag,dboid,reloid,blocknum) \
((locktag).locktag_field1 = (dboid), \ ((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (reloid), \ (locktag).locktag_field2 = (reloid), \
(locktag).locktag_field3 = (blocknum), \ (locktag).locktag_field3 = (blocknum), \
(locktag).locktag_field4 = 0, \ (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) \ #define SET_LOCKTAG_TUPLE(locktag,dboid,reloid,blocknum,offnum) \
((locktag).locktag_field1 = (dboid), \ ((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (reloid), \ (locktag).locktag_field2 = (reloid), \
(locktag).locktag_field3 = (blocknum), \ (locktag).locktag_field3 = (blocknum), \
(locktag).locktag_field4 = (offnum), \ (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) \ #define SET_LOCKTAG_TRANSACTION(locktag,xid) \
((locktag).locktag_field1 = (xid), \ ((locktag).locktag_field1 = (xid), \
(locktag).locktag_field2 = 0, \ (locktag).locktag_field2 = 0, \
(locktag).locktag_field3 = 0, \ (locktag).locktag_field3 = 0, \
(locktag).locktag_field4 = 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) \ #define SET_LOCKTAG_OBJECT(locktag,dboid,classoid,objoid,objsubid) \
((locktag).locktag_field1 = (dboid), \ ((locktag).locktag_field1 = (dboid), \
(locktag).locktag_field2 = (classoid), \ (locktag).locktag_field2 = (classoid), \
(locktag).locktag_field3 = (objoid), \ (locktag).locktag_field3 = (objoid), \
(locktag).locktag_field4 = (objsubid), \ (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 ...@@ -366,18 +388,13 @@ typedef enum
* function prototypes * function prototypes
*/ */
extern void InitLocks(void); extern void InitLocks(void);
extern LockMethod GetLocksMethodTable(LOCK *lock); extern LockMethod GetLocksMethodTable(const LOCK *lock);
extern LOCKMETHODID LockMethodTableInit(const char *tabName, extern LockAcquireResult LockAcquire(const LOCKTAG *locktag,
const LOCKMASK *conflictsP,
int numModes);
extern LOCKMETHODID LockMethodTableRename(LOCKMETHODID lockmethodid);
extern LockAcquireResult LockAcquire(LOCKMETHODID lockmethodid,
LOCKTAG *locktag,
bool isTempObject, bool isTempObject,
LOCKMODE lockmode, LOCKMODE lockmode,
bool sessionLock, bool sessionLock,
bool dontWait); bool dontWait);
extern bool LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, extern bool LockRelease(const LOCKTAG *locktag,
LOCKMODE lockmode, bool sessionLock); LOCKMODE lockmode, bool sessionLock);
extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks); extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
extern void LockReleaseCurrentOwner(void); extern void LockReleaseCurrentOwner(void);
...@@ -399,7 +416,7 @@ extern void RememberSimpleDeadLock(PGPROC *proc1, ...@@ -399,7 +416,7 @@ extern void RememberSimpleDeadLock(PGPROC *proc1,
PGPROC *proc2); PGPROC *proc2);
extern void InitDeadLockChecking(void); extern void InitDeadLockChecking(void);
extern LockData *GetLockStatusData(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, extern void lock_twophase_recover(TransactionId xid, uint16 info,
void *recdata, uint32 len); void *recdata, uint32 len);
......
...@@ -128,31 +128,16 @@ Block</a> - data/index buffer cache block</li> ...@@ -128,31 +128,16 @@ Block</a> - data/index buffer cache block</li>
addresses using table name and block number( <a addresses using table name and block number( <a
href="../../include/storage/buf_internals.h">BufferTag</a>)</li> href="../../include/storage/buf_internals.h">BufferTag</a>)</li>
<li>MultiLevelLockTable (ctl) - control structure for each locking <li>Lock Manager Tables (lock hash) - the <a
method. Currently, only multi-level locking is used(<a
href="../../include/storage/lock.h">LOCKMETHODCTL</a>).</li>
<li>MultiLevelLockTable (lock hash) - the <a
href="../../include/storage/lock.h">LOCK</a> structure, looked up href="../../include/storage/lock.h">LOCK</a> structure, looked up
using relation, database object ids(<a using a <a href="../../include/storage/lock.h">LOCKTAG</a>.
href="../../include/storage/lock.h">LOCKTAG)</a>. The lock table A LOCK structure exists for each lockable object that is currently
structure contains the lock modes(read/write or shared/exclusive) locked by any backend. Also, there is a subsidiary <a
and circular linked list of backends (<a href="../../include/storage/lock.h">PROCLOCK</a> structure for each
href="../../include/storage/proc.h">PROC</a> structure pointers) backend currently interested in a given LOCK</li>
waiting on the lock.</li>
<li><a href="../../include/storage/proc.h">PGPROC Structures</a> -
<li>MultiLevelLockTable (xid hash) - lookup of LOCK structure information about each backend, including locks held/waiting</li>
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>
</ul> </ul>
<p>Each data structure is created by calling <a <p>Each data structure is created by calling <a
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment