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

📄 lock.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*------------------------------------------------------------------------- * * lock.c *	  POSTGRES low-level lock mechanism * * 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/lock.c,v 1.159.2.1 2005/11/22 18:23:18 momjian Exp $ * * NOTES *	  Outside modules can create a lock table and acquire/release *	  locks.  A lock table is a shared memory hash table.  When *	  a process tries to acquire a lock of a type that conflicts *	  with existing locks, it is put to sleep using the routines *	  in storage/lmgr/proc.c. * *	  For the most part, this code should be invoked via lmgr.c *	  or another lock-management module, not directly. * *	Interface: * *	LockAcquire(), LockRelease(), LockMethodTableInit(), *	LockMethodTableRename(), LockReleaseAll(), *	LockCheckConflicts(), GrantLock() * *------------------------------------------------------------------------- */#include "postgres.h"#include <signal.h>#include <unistd.h>#include "access/twophase.h"#include "access/twophase_rmgr.h"#include "access/xact.h"#include "miscadmin.h"#include "storage/proc.h"#include "utils/memutils.h"#include "utils/ps_status.h"#include "utils/resowner.h"/* This configuration variable is used to set the lock table size */int			max_locks_per_xact; /* set by guc.c */#define NLOCKENTS() \	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 */static LockMethod LockMethods[MAX_LOCK_METHODS];static HTAB *LockMethodLockHash[MAX_LOCK_METHODS];static HTAB *LockMethodProcLockHash[MAX_LOCK_METHODS];static HTAB *LockMethodLocalHash[MAX_LOCK_METHODS];/* exported so lmgr.c can initialize it */int			NumLockMethods;/* private state for GrantAwaitedLock */static LOCALLOCK *awaitedLock;static ResourceOwner awaitedOwner;static const char *const lock_mode_names[] ={	"INVALID",	"AccessShareLock",	"RowShareLock",	"RowExclusiveLock",	"ShareUpdateExclusiveLock",	"ShareLock",	"ShareRowExclusiveLock",	"ExclusiveLock",	"AccessExclusiveLock"};#ifdef LOCK_DEBUG/*------ * The following configuration options are available for lock debugging: * *	   TRACE_LOCKS		-- give a bunch of output what's going on in this file *	   TRACE_USERLOCKS	-- same but for user locks *	   TRACE_LOCK_OIDMIN-- do not trace locks for tables below this oid *						   (use to avoid output on system tables) *	   TRACE_LOCK_TABLE -- trace locks on this table (oid) unconditionally *	   DEBUG_DEADLOCKS	-- currently dumps locks at untimely occasions ;) * * Furthermore, but in storage/lmgr/lwlock.c: *	   TRACE_LWLOCKS	-- trace lightweight locks (pretty useless) * * Define LOCK_DEBUG at compile time to get all these enabled. * -------- */int			Trace_lock_oidmin = FirstNormalObjectId;bool		Trace_locks = false;bool		Trace_userlocks = false;int			Trace_lock_table = 0;bool		Debug_deadlocks = false;inline static boolLOCK_DEBUG_ENABLED(const LOCK *lock){	return		(((Trace_locks && LOCK_LOCKMETHOD(*lock) == DEFAULT_LOCKMETHOD)		  || (Trace_userlocks && LOCK_LOCKMETHOD(*lock) == USER_LOCKMETHOD))		 && ((Oid) lock->tag.locktag_field2 >= (Oid) Trace_lock_oidmin))		|| (Trace_lock_table			&& (lock->tag.locktag_field2 == Trace_lock_table));}inline static voidLOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type){	if (LOCK_DEBUG_ENABLED(lock))		elog(LOG,			 "%s: lock(%lx) id(%u,%u,%u,%u,%u,%u) grantMask(%x) "			 "req(%d,%d,%d,%d,%d,%d,%d)=%d "			 "grant(%d,%d,%d,%d,%d,%d,%d)=%d wait(%d) type(%s)",			 where, MAKE_OFFSET(lock),			 lock->tag.locktag_field1, lock->tag.locktag_field2,			 lock->tag.locktag_field3, lock->tag.locktag_field4,			 lock->tag.locktag_type, lock->tag.locktag_lockmethodid,			 lock->grantMask,			 lock->requested[1], lock->requested[2], lock->requested[3],			 lock->requested[4], lock->requested[5], lock->requested[6],			 lock->requested[7], lock->nRequested,			 lock->granted[1], lock->granted[2], lock->granted[3],			 lock->granted[4], lock->granted[5], lock->granted[6],			 lock->granted[7], lock->nGranted,			 lock->waitProcs.size, lock_mode_names[type]);}inline static voidPROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP){	if (LOCK_DEBUG_ENABLED((LOCK *) MAKE_PTR(proclockP->tag.lock)))		elog(LOG,			 "%s: proclock(%lx) lock(%lx) method(%u) proc(%lx) hold(%x)",			 where, MAKE_OFFSET(proclockP), proclockP->tag.lock,			 PROCLOCK_LOCKMETHOD(*(proclockP)),			 proclockP->tag.proc, (int) proclockP->holdMask);}#else							/* not LOCK_DEBUG */#define LOCK_PRINT(where, lock, type)#define PROCLOCK_PRINT(where, proclockP)#endif   /* not LOCK_DEBUG */static void RemoveLocalLock(LOCALLOCK *locallock);static void GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner);static void WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,		   ResourceOwner owner);static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode,			PROCLOCK *proclock, LockMethod lockMethodTable);static void CleanUpLock(LOCKMETHODID lockmethodid, LOCK *lock,			PROCLOCK *proclock, bool wakeupNeeded);/* * InitLocks -- Init the lock module.  Nothing to do here at present. */voidInitLocks(void){	/* NOP */}/* * Fetch the lock method table associated with a given lock */LockMethodGetLocksMethodTable(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 voidLockMethodInit(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. */LOCKMETHODIDLockMethodTableInit(const char *tabName,					const LOCKMASK *conflictsP,					int numModes){	LockMethod	newLockMethod;	LOCKMETHODID lockmethodid;	char	   *shmemName;	HASHCTL		info;	int			hash_flags;	bool		found;	long		init_table_size,				max_table_size;	if (numModes >= MAX_LOCKMODES)		elog(ERROR, "too many lock types %d (limit is %d)",			 numModes, MAX_LOCKMODES - 1);	/* Compute init/max size to request for lock hashtables */	max_table_size = NLOCKENTS();	init_table_size = max_table_size / 2;	/* Allocate a string for the shmem index table lookups. */	/* This is just temp space in this routine, so palloc is OK. */	shmemName = (char *) palloc(strlen(tabName) + 32);	/* each lock table has a header in shared memory */	sprintf(shmemName, "%s (lock method table)", tabName);	newLockMethod = (LockMethod)		ShmemInitStruct(shmemName, sizeof(LockMethodData), &found);	if (!newLockMethod)		elog(FATAL, "could not initialize lock table \"%s\"", tabName);	/*	 * we're first - initialize	 */	if (!found)	{		MemSet(newLockMethod, 0, sizeof(LockMethodData));		newLockMethod->masterLock = LockMgrLock;		LockMethodInit(newLockMethod, conflictsP, numModes);	}	/*	 * other modules refer to the lock table by a lockmethod ID	 */	Assert(NumLockMethods < MAX_LOCK_METHODS);	lockmethodid = NumLockMethods++;	LockMethods[lockmethodid] = newLockMethod;	/*	 * allocate a hash table for LOCK structs.	This is used to store	 * per-locked-object information.	 */	MemSet(&info, 0, sizeof(info));	info.keysize = sizeof(LOCKTAG);	info.entrysize = sizeof(LOCK);	info.hash = tag_hash;	hash_flags = (HASH_ELEM | HASH_FUNCTION);	sprintf(shmemName, "%s (lock hash)", tabName);	LockMethodLockHash[lockmethodid] = ShmemInitHash(shmemName,													 init_table_size,													 max_table_size,													 &info,													 hash_flags);	if (!LockMethodLockHash[lockmethodid])		elog(FATAL, "could not initialize lock table \"%s\"", tabName);	/*	 * allocate a hash table for PROCLOCK structs.	This is used to store	 * per-lock-holder information.	 */	info.keysize = sizeof(PROCLOCKTAG);	info.entrysize = sizeof(PROCLOCK);	info.hash = tag_hash;	hash_flags = (HASH_ELEM | HASH_FUNCTION);	sprintf(shmemName, "%s (proclock hash)", tabName);	LockMethodProcLockHash[lockmethodid] = ShmemInitHash(shmemName,														 init_table_size,														 max_table_size,														 &info,														 hash_flags);	if (!LockMethodProcLockHash[lockmethodid])		elog(FATAL, "could not initialize lock table \"%s\"", tabName);	/*	 * allocate a non-shared hash table for LOCALLOCK structs.	This is used	 * to store lock counts and resource owner information.	 *	 * The non-shared table could already exist in this process (this occurs	 * when the postmaster is recreating shared memory after a backend crash).	 * If so, delete and recreate it.  (We could simply leave it, since it	 * ought to be empty in the postmaster, but for safety let's zap it.)	 */	if (LockMethodLocalHash[lockmethodid])		hash_destroy(LockMethodLocalHash[lockmethodid]);	info.keysize = sizeof(LOCALLOCKTAG);	info.entrysize = sizeof(LOCALLOCK);	info.hash = tag_hash;	hash_flags = (HASH_ELEM | HASH_FUNCTION);	sprintf(shmemName, "%s (locallock hash)", tabName);	LockMethodLocalHash[lockmethodid] = hash_create(shmemName,													128,													&info,													hash_flags);	pfree(shmemName);	return lockmethodid;}/* * LockMethodTableRename -- allocate another lockmethod ID to the same *		lock table. * * NOTES: This function makes it possible to have different lockmethodids, *		and hence different locking semantics, while still storing all *		the data in one shared-memory hashtable. */LOCKMETHODIDLockMethodTableRename(LOCKMETHODID lockmethodid){	LOCKMETHODID newLockMethodId;	if (NumLockMethods >= MAX_LOCK_METHODS)		return INVALID_LOCKMETHOD;	if (LockMethods[lockmethodid] == INVALID_LOCKMETHOD)		return INVALID_LOCKMETHOD;	/* other modules refer to the lock table by a lockmethod ID */	newLockMethodId = NumLockMethods;	NumLockMethods++;	LockMethods[newLockMethodId] = LockMethods[lockmethodid];	LockMethodLockHash[newLockMethodId] = LockMethodLockHash[lockmethodid];	LockMethodProcLockHash[newLockMethodId] = LockMethodProcLockHash[lockmethodid];	LockMethodLocalHash[newLockMethodId] = LockMethodLocalHash[lockmethodid];	return newLockMethodId;}/* * LockAcquire -- Check for lock conflicts, sleep if conflict found, *		set lock if/when no conflicts. * * Inputs: *	lockmethodid: identifies which lock table to use *	locktag: unique identifier for the lockable object *	isTempObject: is the lockable object a temporary object?  (Under 2PC, *		such locks cannot be persisted) *	lockmode: lock mode to acquire *	sessionLock: if true, acquire lock for session not current transaction *	dontWait: if true, don't wait to acquire lock * * Returns one of: *		LOCKACQUIRE_NOT_AVAIL		lock not available, and dontWait=true *		LOCKACQUIRE_OK				lock successfully acquired *		LOCKACQUIRE_ALREADY_HELD	incremented count for lock already held * * In the normal case where dontWait=false and the caller doesn't need to * distinguish a freshly acquired lock from one already taken earlier in * this same transaction, there is no need to examine the return value. * * Side Effects: The lock is acquired and recorded in lock tables. * * NOTE: if we wait for the lock, there is no way to abort the wait * short of aborting the transaction. * * * Note on User Locks: * *		User locks are handled totally on the application side as *		long term cooperative locks which extend beyond the normal *		transaction boundaries.  Their purpose is to indicate to an *		application that someone is `working' on an item.  So it is *		possible to put an user lock on a tuple's oid, retrieve the *		tuple, work on it for an hour and then update it and remove *		the lock.  While the lock is active other clients can still *		read and write the tuple but they can be aware that it has *		been locked at the application level by someone. * *		User locks and normal locks are completely orthogonal and *		they don't interfere with each other. * *		User locks are always non blocking, therefore they are never *		acquired if already held by another process.  They must be *		released explicitly by the application but they are released *		automatically when a backend terminates. *		They are indicated by a lockmethod 2 which is an alias for the *		normal lock table. * *		The lockmode parameter can have the same values for normal locks *		although probably only WRITE_LOCK can have some practical use. * *														DZ - 22 Nov 1997 */LockAcquireResultLockAcquire(LOCKMETHODID lockmethodid,			LOCKTAG *locktag,			bool isTempObject,			LOCKMODE lockmode,			bool sessionLock,			bool dontWait){	LOCALLOCKTAG localtag;	LOCALLOCK  *locallock;	LOCK	   *lock;	PROCLOCK   *proclock;	PROCLOCKTAG proclocktag;	bool		found;	ResourceOwner owner;	LWLockId	masterLock;	LockMethod	lockMethodTable;	int			status;

⌨️ 快捷键说明

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