⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lmgr.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
字号:
/*------------------------------------------------------------------------- * * lmgr.c *	  POSTGRES lock manager code * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.79 2005/10/15 02:49:26 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#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 */voidInitLockTable(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. * *		relcache.c must call this during creation of any reldesc. */voidRelationInitLockInfo(Relation relation){	Assert(RelationIsValid(relation));	Assert(OidIsValid(RelationGetRelid(relation)));	relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);	if (relation->rd_rel->relisshared)		relation->rd_lockInfo.lockRelId.dbId = InvalidOid;	else		relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;}/* *		LockRelation */voidLockRelation(Relation relation, LOCKMODE lockmode){	LOCKTAG		tag;	LockAcquireResult res;	SET_LOCKTAG_RELATION(tag,						 relation->rd_lockInfo.lockRelId.dbId,						 relation->rd_lockInfo.lockRelId.relId);	res = LockAcquire(LockTableId, &tag, relation->rd_istemp,					  lockmode, false, false);	/*	 * Check to see if the relcache entry has been invalidated while we were	 * waiting to lock it.	If so, rebuild it, or ereport() trying. Increment	 * the refcount to ensure that RelationFlushRelation will rebuild it and	 * not just delete it.	We can skip this if the lock was already held,	 * however.	 */	if (res != LOCKACQUIRE_ALREADY_HELD)	{		RelationIncrementReferenceCount(relation);		AcceptInvalidationMessages();		RelationDecrementReferenceCount(relation);	}}/* *		ConditionalLockRelation * * As above, but only lock if we can get the lock without blocking. * Returns TRUE iff the lock was acquired. * * NOTE: we do not currently need conditional versions of all the * LockXXX routines in this file, but they could easily be added if needed. */boolConditionalLockRelation(Relation relation, LOCKMODE lockmode){	LOCKTAG		tag;	LockAcquireResult res;	SET_LOCKTAG_RELATION(tag,						 relation->rd_lockInfo.lockRelId.dbId,						 relation->rd_lockInfo.lockRelId.relId);	res = LockAcquire(LockTableId, &tag, relation->rd_istemp,					  lockmode, false, true);	if (res == LOCKACQUIRE_NOT_AVAIL)		return false;	/*	 * Check to see if the relcache entry has been invalidated while we were	 * waiting to lock it.	If so, rebuild it, or ereport() trying. Increment	 * the refcount to ensure that RelationFlushRelation will rebuild it and	 * not just delete it.	We can skip this if the lock was already held,	 * however.	 */	if (res != LOCKACQUIRE_ALREADY_HELD)	{		RelationIncrementReferenceCount(relation);		AcceptInvalidationMessages();		RelationDecrementReferenceCount(relation);	}	return true;}/* *		UnlockRelation */voidUnlockRelation(Relation relation, LOCKMODE lockmode){	LOCKTAG		tag;	SET_LOCKTAG_RELATION(tag,						 relation->rd_lockInfo.lockRelId.dbId,						 relation->rd_lockInfo.lockRelId.relId);	LockRelease(LockTableId, &tag, lockmode, false);}/* *		LockRelationForSession * * This routine grabs a session-level lock on the target relation.	The * session lock persists across transaction boundaries.  It will be removed * when UnlockRelationForSession() is called, or if an ereport(ERROR) occurs, * or if the backend exits. * * Note that one should also grab a transaction-level lock on the rel * in any transaction that actually uses the rel, to ensure that the * relcache entry is up to date. */voidLockRelationForSession(LockRelId *relid, bool istemprel, LOCKMODE lockmode){	LOCKTAG		tag;	SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);	(void) LockAcquire(LockTableId, &tag, istemprel,					   lockmode, true, false);}/* *		UnlockRelationForSession */voidUnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode){	LOCKTAG		tag;	SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);	LockRelease(LockTableId, &tag, lockmode, true);}/* *		LockRelationForExtension * * This lock tag is used to interlock addition of pages to relations. * We need such locking because bufmgr/smgr definition of P_NEW is not * race-condition-proof. * * We assume the caller is already holding some type of regular lock on * the relation, so no AcceptInvalidationMessages call is needed here. */voidLockRelationForExtension(Relation relation, LOCKMODE lockmode){	LOCKTAG		tag;	SET_LOCKTAG_RELATION_EXTEND(tag,								relation->rd_lockInfo.lockRelId.dbId,								relation->rd_lockInfo.lockRelId.relId);	(void) LockAcquire(LockTableId, &tag, relation->rd_istemp,					   lockmode, false, false);}/* *		UnlockRelationForExtension */voidUnlockRelationForExtension(Relation relation, LOCKMODE lockmode){	LOCKTAG		tag;	SET_LOCKTAG_RELATION_EXTEND(tag,								relation->rd_lockInfo.lockRelId.dbId,								relation->rd_lockInfo.lockRelId.relId);	LockRelease(LockTableId, &tag, lockmode, false);}/* *		LockPage * * Obtain a page-level lock.  This is currently used by some index access * methods to lock individual index pages. */voidLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode){	LOCKTAG		tag;	SET_LOCKTAG_PAGE(tag,					 relation->rd_lockInfo.lockRelId.dbId,					 relation->rd_lockInfo.lockRelId.relId,					 blkno);	(void) LockAcquire(LockTableId, &tag, relation->rd_istemp,					   lockmode, false, false);}/* *		ConditionalLockPage * * As above, but only lock if we can get the lock without blocking. * Returns TRUE iff the lock was acquired. */boolConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode){	LOCKTAG		tag;	SET_LOCKTAG_PAGE(tag,					 relation->rd_lockInfo.lockRelId.dbId,					 relation->rd_lockInfo.lockRelId.relId,					 blkno);	return (LockAcquire(LockTableId, &tag, relation->rd_istemp,						lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);}/* *		UnlockPage */voidUnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode){	LOCKTAG		tag;	SET_LOCKTAG_PAGE(tag,					 relation->rd_lockInfo.lockRelId.dbId,					 relation->rd_lockInfo.lockRelId.relId,					 blkno);	LockRelease(LockTableId, &tag, lockmode, false);}/* *		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! */voidLockTuple(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));	(void) LockAcquire(LockTableId, &tag, relation->rd_istemp,					   lockmode, false, false);}/* *		ConditionalLockTuple * * As above, but only lock if we can get the lock without blocking. * Returns TRUE iff the lock was acquired. */boolConditionalLockTuple(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));	return (LockAcquire(LockTableId, &tag, relation->rd_istemp,						lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);}/* *		UnlockTuple */voidUnlockTuple(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, lockmode, false);}/* *		XactLockTableInsert * * Insert a lock showing that the given transaction ID is running --- * this is done during xact startup.  The lock can then be used to wait * for the transaction to finish. */voidXactLockTableInsert(TransactionId xid){	LOCKTAG		tag;	SET_LOCKTAG_TRANSACTION(tag, xid);	(void) LockAcquire(LockTableId, &tag, false,					   ExclusiveLock, false, false);}/* *		XactLockTableDelete * * Delete the lock showing that the given transaction ID is running. * (This is never used for main transaction IDs; those locks are only * released implicitly at transaction end.	But we do use it for subtrans * IDs.) */voidXactLockTableDelete(TransactionId xid){	LOCKTAG		tag;	SET_LOCKTAG_TRANSACTION(tag, xid);	LockRelease(LockTableId, &tag, ExclusiveLock, false);}/* *		XactLockTableWait * * Wait for the specified transaction to commit or abort. * * Note that this does the right thing for subtransactions: if we wait on a * subtransaction, we will exit as soon as it aborts or its top parent commits. * It takes some extra work to ensure this, because to save on shared memory * the XID lock of a subtransaction is released when it ends, whether * successfully or unsuccessfully.	So we have to check if it's "still running" * and if so wait for its parent. */voidXactLockTableWait(TransactionId xid){	LOCKTAG		tag;	for (;;)	{		Assert(TransactionIdIsValid(xid));		Assert(!TransactionIdEquals(xid, GetTopTransactionId()));		SET_LOCKTAG_TRANSACTION(tag, xid);		(void) LockAcquire(LockTableId, &tag, false,						   ShareLock, false, false);		LockRelease(LockTableId, &tag, ShareLock, false);		if (!TransactionIdIsInProgress(xid))			break;		xid = SubTransGetParent(xid);	}	/*	 * Transaction was committed/aborted/crashed - we have to update pg_clog	 * if transaction is still marked as running.	 */	if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))		TransactionIdAbort(xid);}/* *		ConditionalXactLockTableWait * * As above, but only lock if we can get the lock without blocking. * Returns TRUE if the lock was acquired. */boolConditionalXactLockTableWait(TransactionId xid){	LOCKTAG		tag;	for (;;)	{		Assert(TransactionIdIsValid(xid));		Assert(!TransactionIdEquals(xid, GetTopTransactionId()));		SET_LOCKTAG_TRANSACTION(tag, xid);		if (LockAcquire(LockTableId, &tag, false,						ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)			return false;		LockRelease(LockTableId, &tag, ShareLock, false);		if (!TransactionIdIsInProgress(xid))			break;		xid = SubTransGetParent(xid);	}	/*	 * Transaction was committed/aborted/crashed - we have to update pg_clog	 * if transaction is still marked as running.	 */	if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid))		TransactionIdAbort(xid);	return true;}/* *		LockDatabaseObject * * Obtain a lock on a general object of the current database.  Don't use * this for shared objects (such as tablespaces).  It's unwise to apply it * to relations, also, since a lock taken this way will NOT conflict with * LockRelation, and also may be wrongly marked if the relation is temp. * (If we ever invent temp objects that aren't tables, we'll want to extend * the API of this routine to include an isTempObject flag.) */voidLockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,				   LOCKMODE lockmode){	LOCKTAG		tag;	SET_LOCKTAG_OBJECT(tag,					   MyDatabaseId,					   classid,					   objid,					   objsubid);	(void) LockAcquire(LockTableId, &tag, false,					   lockmode, false, false);}/* *		UnlockDatabaseObject */voidUnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,					 LOCKMODE lockmode){	LOCKTAG		tag;	SET_LOCKTAG_OBJECT(tag,					   MyDatabaseId,					   classid,					   objid,					   objsubid);	LockRelease(LockTableId, &tag, lockmode, false);}/* *		LockSharedObject * * Obtain a lock on a shared-across-databases object. */voidLockSharedObject(Oid classid, Oid objid, uint16 objsubid,				 LOCKMODE lockmode){	LOCKTAG		tag;	SET_LOCKTAG_OBJECT(tag,					   InvalidOid,					   classid,					   objid,					   objsubid);	(void) LockAcquire(LockTableId, &tag, false,					   lockmode, false, false);}/* *		UnlockSharedObject */voidUnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,				   LOCKMODE lockmode){	LOCKTAG		tag;	SET_LOCKTAG_OBJECT(tag,					   InvalidOid,					   classid,					   objid,					   objsubid);	LockRelease(LockTableId, &tag, lockmode, false);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -