Commit 93b24772 authored by Tom Lane's avatar Tom Lane

Use the standard lock manager to establish priority order when there

is contention for a tuple-level lock.  This solves the problem of a
would-be exclusive locker being starved out by an indefinite succession
of share-lockers.  Per recent discussion with Alvaro.
parent 47458f8c
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.72 2005/04/29 22:28:24 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.73 2005/04/30 19:03:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -339,6 +339,46 @@ UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode) ...@@ -339,6 +339,46 @@ UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode); LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
} }
/*
* LockTuple
*
* Obtain a tuple-level lock. This is used in a less-than-intuitive fashion
* because we can't afford to keep a separate lock in shared memory for every
* tuple. See heap_lock_tuple before using this!
*/
void
LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
{
LOCKTAG tag;
SET_LOCKTAG_TUPLE(tag,
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId,
ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid));
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
lockmode, false))
elog(ERROR, "LockAcquire failed");
}
/*
* UnlockTuple
*/
void
UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
{
LOCKTAG tag;
SET_LOCKTAG_TUPLE(tag,
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId,
ItemPointerGetBlockNumber(tid),
ItemPointerGetOffsetNumber(tid));
LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
}
/* /*
* XactLockTableInsert * XactLockTableInsert
* *
...@@ -417,3 +457,87 @@ XactLockTableWait(TransactionId xid) ...@@ -417,3 +457,87 @@ XactLockTableWait(TransactionId xid)
if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid)) if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))
TransactionIdAbort(xid); TransactionIdAbort(xid);
} }
/*
* LockDatabaseObject
*
* Obtain a lock on a general object of the current database. Don't use
* this for shared objects (such as tablespaces). It's usually unwise to
* apply it to entire relations, also, since a lock taken this way will
* NOT conflict with LockRelation.
*/
void
LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
LOCKMODE lockmode)
{
LOCKTAG tag;
SET_LOCKTAG_OBJECT(tag,
MyDatabaseId,
classid,
objid,
objsubid);
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
lockmode, false))
elog(ERROR, "LockAcquire failed");
}
/*
* UnlockDatabaseObject
*/
void
UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
LOCKMODE lockmode)
{
LOCKTAG tag;
SET_LOCKTAG_OBJECT(tag,
MyDatabaseId,
classid,
objid,
objsubid);
LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
}
/*
* LockSharedObject
*
* Obtain a lock on a shared-across-databases object.
*/
void
LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
LOCKMODE lockmode)
{
LOCKTAG tag;
SET_LOCKTAG_OBJECT(tag,
InvalidOid,
classid,
objid,
objsubid);
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
lockmode, false))
elog(ERROR, "LockAcquire failed");
}
/*
* UnlockSharedObject
*/
void
UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
LOCKMODE lockmode)
{
LOCKTAG tag;
SET_LOCKTAG_OBJECT(tag,
InvalidOid,
classid,
objid,
objsubid);
LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
}
...@@ -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.47 2005/04/29 22:28:24 tgl Exp $ * $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.48 2005/04/30 19:03:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "storage/lock.h" #include "storage/lock.h"
#include "utils/rel.h" #include "utils/rel.h"
/* These are the valid values of type LOCKMODE: */ /* These are the valid values of type LOCKMODE: */
/* NoLock is not a lock mode, but a flag value meaning "don't get a lock" */ /* NoLock is not a lock mode, but a flag value meaning "don't get a lock" */
...@@ -60,9 +61,25 @@ extern void LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode); ...@@ -60,9 +61,25 @@ extern void LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
extern bool ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode); extern bool ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode); extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
/* Lock a tuple (see heap_lock_tuple before assuming you understand this) */
extern void LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode);
extern void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode);
/* Lock an XID (used to wait for a transaction to finish) */ /* Lock an XID (used to wait for a transaction to finish) */
extern void XactLockTableInsert(TransactionId xid); extern void XactLockTableInsert(TransactionId xid);
extern void XactLockTableDelete(TransactionId xid); extern void XactLockTableDelete(TransactionId xid);
extern void XactLockTableWait(TransactionId xid); extern void XactLockTableWait(TransactionId xid);
/* Lock a general object (other than a relation) of the current database */
extern void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
LOCKMODE lockmode);
extern void UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
LOCKMODE lockmode);
/* Lock a shared-across-databases object (other than a relation) */
extern void LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
LOCKMODE lockmode);
extern void UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
LOCKMODE lockmode);
#endif /* LMGR_H */ #endif /* LMGR_H */
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