mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
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.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,96 +18,12 @@
|
||||
#include "access/subtrans.h"
|
||||
#include "access/transam.h"
|
||||
#include "access/xact.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "miscadmin.h"
|
||||
#include "storage/lmgr.h"
|
||||
#include "storage/procarray.h"
|
||||
#include "utils/inval.h"
|
||||
|
||||
|
||||
/*
|
||||
* This conflict table defines the semantics of the various lock modes.
|
||||
*/
|
||||
static const LOCKMASK LockConflicts[] = {
|
||||
0,
|
||||
|
||||
/* AccessShareLock */
|
||||
(1 << AccessExclusiveLock),
|
||||
|
||||
/* RowShareLock */
|
||||
(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
|
||||
|
||||
/* RowExclusiveLock */
|
||||
(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
|
||||
(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
|
||||
|
||||
/* ShareUpdateExclusiveLock */
|
||||
(1 << ShareUpdateExclusiveLock) |
|
||||
(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
|
||||
(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
|
||||
|
||||
/* ShareLock */
|
||||
(1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
|
||||
(1 << ShareRowExclusiveLock) |
|
||||
(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
|
||||
|
||||
/* ShareRowExclusiveLock */
|
||||
(1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
|
||||
(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
|
||||
(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
|
||||
|
||||
/* ExclusiveLock */
|
||||
(1 << RowShareLock) |
|
||||
(1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
|
||||
(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
|
||||
(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
|
||||
|
||||
/* AccessExclusiveLock */
|
||||
(1 << AccessShareLock) | (1 << RowShareLock) |
|
||||
(1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
|
||||
(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
|
||||
(1 << ExclusiveLock) | (1 << AccessExclusiveLock)
|
||||
|
||||
};
|
||||
|
||||
static LOCKMETHODID LockTableId = INVALID_LOCKMETHOD;
|
||||
|
||||
|
||||
/*
|
||||
* Create the lock table described by LockConflicts
|
||||
*/
|
||||
void
|
||||
InitLockTable(void)
|
||||
{
|
||||
LOCKMETHODID LongTermTableId;
|
||||
|
||||
/* there's no zero-th table */
|
||||
NumLockMethods = 1;
|
||||
|
||||
/*
|
||||
* Create the default lock method table
|
||||
*/
|
||||
|
||||
/* number of lock modes is lengthof()-1 because of dummy zero */
|
||||
LockTableId = LockMethodTableInit("LockTable",
|
||||
LockConflicts,
|
||||
lengthof(LockConflicts) - 1);
|
||||
if (!LockMethodIsValid(LockTableId))
|
||||
elog(ERROR, "could not initialize lock table");
|
||||
Assert(LockTableId == DEFAULT_LOCKMETHOD);
|
||||
|
||||
#ifdef USER_LOCKS
|
||||
|
||||
/*
|
||||
* Allocate another tableId for user locks (same shared hashtable though)
|
||||
*/
|
||||
LongTermTableId = LockMethodTableRename(LockTableId);
|
||||
if (!LockMethodIsValid(LongTermTableId))
|
||||
elog(ERROR, "could not rename user lock table");
|
||||
Assert(LongTermTableId == USER_LOCKMETHOD);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* RelationInitLockInfo
|
||||
* Initializes the lock information in a relation descriptor.
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
4
src/backend/utils/cache/relcache.c
vendored
4
src/backend/utils/cache/relcache.c
vendored
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user