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

📄 lock.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * lock.c *	  simple lock acquisition * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.55 1999/05/29 06:14:42 vadim 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 conflictRs *	  with existing locks, it is put to sleep using the routines *	  in storage/lmgr/proc.c. * *	Interface: * *	LockAcquire(), LockRelease(), LockMethodTableInit(), *	LockMethodTableRename(), LockReleaseAll, LockOwners() *	LockResolveConflicts(), GrantLock() * *	NOTE: This module is used to define new lock tables.  The *		multi-level lock table (multi.c) used by the heap *		access methods calls these routines.  See multi.c for *		examples showing how to use this interface. * *------------------------------------------------------------------------- */#include <stdio.h>				/* for sprintf() */#include <string.h>#include <sys/types.h>#include <unistd.h>#include <signal.h>#include "postgres.h"#include "miscadmin.h"#include "storage/shmem.h"#include "storage/sinvaladt.h"#include "storage/spin.h"#include "storage/proc.h"#include "storage/lock.h"#include "utils/hsearch.h"#include "utils/memutils.h"#include "utils/palloc.h"#include "access/xact.h"#include "access/transam.h"#include "utils/trace.h"#include "utils/ps_status.h"static int	WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode);/* * lockDebugRelation can be used to trace unconditionally a single relation, * for example pg_listener, if you suspect there are locking problems. * * lockDebugOidMin is is used to avoid tracing postgres relations, which * would produce a lot of output. Unfortunately most system relations are * created after bootstrap and have oid greater than BootstrapObjectIdData. * If you are using tprintf you should specify a value greater than the max * oid of system relations, which can be found with the following query: * *	 select max(int4in(int4out(oid))) from pg_class where relname ~ '^pg_'; * * To get a useful lock trace you can use the following pg_options: * *	 -T "verbose,query,locks,userlocks,lock_debug_oidmin=17500" */#define LOCKDEBUG(lockmethod)	(pg_options[TRACE_SHORTLOCKS+lockmethod])#define lockDebugRelation		(pg_options[TRACE_LOCKRELATION])#define lockDebugOidMin			(pg_options[TRACE_LOCKOIDMIN])#define lockReadPriority		(pg_options[OPT_LOCKREADPRIORITY])#ifdef LOCK_MGR_DEBUG#define LOCK_PRINT(where,lock,type) \	if (((LOCKDEBUG(LOCK_LOCKMETHOD(*(lock))) >= 1) \		 && (lock->tag.relId >= lockDebugOidMin)) \		|| \		(lockDebugRelation && (lock->tag.relId == lockDebugRelation))) \		LOCK_PRINT_AUX(where,lock,type)#define LOCK_PRINT_AUX(where,lock,type) \	TPRINTF(TRACE_ALL, \		 "%s: lock(%x) tbl(%d) rel(%u) db(%u) obj(%u) mask(%x) " \		 "hold(%d,%d,%d,%d,%d,%d,%d)=%d " \		 "act(%d,%d,%d,%d,%d,%d,%d)=%d wait(%d) type(%s)", \		 where, \		 MAKE_OFFSET(lock), \		 lock->tag.lockmethod, \		 lock->tag.relId, \		 lock->tag.dbId, \		 lock->tag.objId.blkno, \		 lock->mask, \		 lock->holders[1], \		 lock->holders[2], \		 lock->holders[3], \		 lock->holders[4], \		 lock->holders[5], \		 lock->holders[6], \		 lock->holders[7], \		 lock->nHolding, \		 lock->activeHolders[1], \		 lock->activeHolders[2], \		 lock->activeHolders[3], \		 lock->activeHolders[4], \		 lock->activeHolders[5], \		 lock->activeHolders[6], \		 lock->activeHolders[7], \		 lock->nActive, \		 lock->waitProcs.size, \		 lock_types[type])#define XID_PRINT(where,xidentP) \	if (((LOCKDEBUG(XIDENT_LOCKMETHOD(*(xidentP))) >= 1) \		 && (((LOCK *)MAKE_PTR(xidentP->tag.lock))->tag.relId \			 >= lockDebugOidMin)) \		|| (lockDebugRelation && \			(((LOCK *)MAKE_PTR(xidentP->tag.lock))->tag.relId \			 == lockDebugRelation))) \		XID_PRINT_AUX(where,xidentP)#define XID_PRINT_AUX(where,xidentP) \	TPRINTF(TRACE_ALL, \		 "%s: xid(%x) lock(%x) tbl(%d) pid(%d) xid(%u) " \		 "hold(%d,%d,%d,%d,%d,%d,%d)=%d", \		 where, \		 MAKE_OFFSET(xidentP), \		 xidentP->tag.lock, \		 XIDENT_LOCKMETHOD(*(xidentP)), \		 xidentP->tag.pid, \		 xidentP->tag.xid, \		 xidentP->holders[1], \		 xidentP->holders[2], \		 xidentP->holders[3], \		 xidentP->holders[4], \		 xidentP->holders[5], \		 xidentP->holders[6], \		 xidentP->holders[7], \		 xidentP->nHolding)#else							/* !LOCK_MGR_DEBUG */#define LOCK_PRINT(where,lock,type)#define LOCK_PRINT_AUX(where,lock,type)#define XID_PRINT(where,xidentP)#define XID_PRINT_AUX(where,xidentP)#endif	 /* !LOCK_MGR_DEBUG */static char *lock_types[] = {	"INVALID",	"AccessShareLock",	"RowShareLock",	"RowExclusiveLock",	"ShareLock",	"ShareRowExclusiveLock",	"ExclusiveLock",	"AccessExclusiveLock"};SPINLOCK	LockMgrLock;		/* in Shmem or created in								 * CreateSpinlocks() *//* This is to simplify/speed up some bit arithmetic */static MASK BITS_OFF[MAX_LOCKMODES];static MASK BITS_ON[MAX_LOCKMODES];/* ----------------- * XXX Want to move this to this file * ----------------- */static bool LockingIsDisabled;/* ------------------- * map from lockmethod to the lock table structure * ------------------- */static LOCKMETHODTABLE *LockMethodTable[MAX_LOCK_METHODS];static int	NumLockMethods;/* ------------------- * InitLocks -- Init the lock module.  Create a private data *		structure for constructing conflict masks. * ------------------- */voidInitLocks(){	int			i;	int			bit;	bit = 1;	/* -------------------	 * remember 0th lockmode is invalid	 * -------------------	 */	for (i = 0; i < MAX_LOCKMODES; i++, bit <<= 1)	{		BITS_ON[i] = bit;		BITS_OFF[i] = ~bit;	}#ifdef LOCK_MGR_DEBUG	/*	 * If lockDebugOidMin value has not been specified in pg_options set a	 * default value.	 */	if (!lockDebugOidMin)		lockDebugOidMin = BootstrapObjectIdData;#endif}/* ------------------- * LockDisable -- sets LockingIsDisabled flag to TRUE or FALSE. * ------------------ */voidLockDisable(int status){	LockingIsDisabled = status;}/* * LockMethodInit -- initialize the lock table's lock type *		structures * * Notes: just copying.  Should only be called once. */static voidLockMethodInit(LOCKMETHODTABLE *lockMethodTable,			   MASK *conflictsP,			   int *prioP,			   int numModes){	int			i;	lockMethodTable->ctl->numLockModes = numModes;	numModes++;	for (i = 0; i < numModes; i++, prioP++, conflictsP++)	{		lockMethodTable->ctl->conflictTab[i] = *conflictsP;		lockMethodTable->ctl->prio[i] = *prioP;	}}/* * LockMethodTableInit -- initialize a lock table structure * * Notes: *		(a) a lock table has four separate entries in the shmem index *		table.	This is because every shared hash table and spinlock *		has its name stored in the shmem index at its creation.  It *		is wasteful, in this case, but not much space is involved. * */LOCKMETHODLockMethodTableInit(char *tabName,					MASK *conflictsP,					int *prioP,					int numModes){	LOCKMETHODTABLE *lockMethodTable;	char	   *shmemName;	HASHCTL		info;	int			hash_flags;	bool		found;	int			status = TRUE;	if (numModes > MAX_LOCKMODES)	{		elog(NOTICE, "LockMethodTableInit: too many lock types %d greater than %d",			 numModes, MAX_LOCKMODES);		return INVALID_LOCKMETHOD;	}	/* allocate a string for the shmem index table lookup */	shmemName = (char *) palloc((unsigned) (strlen(tabName) + 32));	if (!shmemName)	{		elog(NOTICE, "LockMethodTableInit: couldn't malloc string %s \n", tabName);		return INVALID_LOCKMETHOD;	}	/* each lock table has a non-shared header */	lockMethodTable = (LOCKMETHODTABLE *) palloc((unsigned) sizeof(LOCKMETHODTABLE));	if (!lockMethodTable)	{		elog(NOTICE, "LockMethodTableInit: couldn't malloc lock table %s\n", tabName);		pfree(shmemName);		return INVALID_LOCKMETHOD;	}	/* ------------------------	 * find/acquire the spinlock for the table	 * ------------------------	 */	SpinAcquire(LockMgrLock);	/* -----------------------	 * allocate a control structure from shared memory or attach to it	 * if it already exists.	 * -----------------------	 */	sprintf(shmemName, "%s (ctl)", tabName);	lockMethodTable->ctl = (LOCKMETHODCTL *)		ShmemInitStruct(shmemName, (unsigned) sizeof(LOCKMETHODCTL), &found);	if (!lockMethodTable->ctl)	{		elog(FATAL, "LockMethodTableInit: couldn't initialize %s", tabName);		status = FALSE;	}	/* -------------------	 * no zero-th table	 * -------------------	 */	NumLockMethods = 1;	/* ----------------	 * we're first - initialize	 * ----------------	 */	if (!found)	{		MemSet(lockMethodTable->ctl, 0, sizeof(LOCKMETHODCTL));		lockMethodTable->ctl->masterLock = LockMgrLock;		lockMethodTable->ctl->lockmethod = NumLockMethods;	}	/* --------------------	 * other modules refer to the lock table by a lockmethod	 * --------------------	 */	LockMethodTable[NumLockMethods] = lockMethodTable;	NumLockMethods++;	Assert(NumLockMethods <= MAX_LOCK_METHODS);	/* ----------------------	 * allocate a hash table for the lock tags.  This is used	 * to find the different locks.	 * ----------------------	 */	info.keysize = SHMEM_LOCKTAB_KEYSIZE;	info.datasize = SHMEM_LOCKTAB_DATASIZE;	info.hash = tag_hash;	hash_flags = (HASH_ELEM | HASH_FUNCTION);	sprintf(shmemName, "%s (lock hash)", tabName);	lockMethodTable->lockHash = (HTAB *) ShmemInitHash(shmemName,										 INIT_TABLE_SIZE, MAX_TABLE_SIZE,													   &info, hash_flags);	Assert(lockMethodTable->lockHash->hash == tag_hash);	if (!lockMethodTable->lockHash)	{		elog(FATAL, "LockMethodTableInit: couldn't initialize %s", tabName);		status = FALSE;	}	/* -------------------------	 * allocate an xid table.  When different transactions hold	 * the same lock, additional information must be saved (locks per tx).	 * -------------------------	 */	info.keysize = SHMEM_XIDTAB_KEYSIZE;	info.datasize = SHMEM_XIDTAB_DATASIZE;	info.hash = tag_hash;	hash_flags = (HASH_ELEM | HASH_FUNCTION);	sprintf(shmemName, "%s (xid hash)", tabName);	lockMethodTable->xidHash = (HTAB *) ShmemInitHash(shmemName,										 INIT_TABLE_SIZE, MAX_TABLE_SIZE,													  &info, hash_flags);	if (!lockMethodTable->xidHash)	{		elog(FATAL, "LockMethodTableInit: couldn't initialize %s", tabName);		status = FALSE;	}	/* init ctl data structures */	LockMethodInit(lockMethodTable, conflictsP, prioP, numModes);	SpinRelease(LockMgrLock);	pfree(shmemName);	if (status)		return lockMethodTable->ctl->lockmethod;	else		return INVALID_LOCKMETHOD;}/* * LockMethodTableRename -- allocate another lockmethod to the same *		lock table. * * NOTES: Both the lock module and the lock chain (lchain.c) *		module use table id's to distinguish between different *		kinds of locks.  Short term and long term locks look *		the same to the lock table, but are handled differently *		by the lock chain manager.	This function allows the *		client to use different lockmethods when acquiring/releasing *		short term and long term locks. */LOCKMETHODLockMethodTableRename(LOCKMETHOD lockmethod){	LOCKMETHOD	newLockMethod;	if (NumLockMethods >= MAX_LOCK_METHODS)		return INVALID_LOCKMETHOD;	if (LockMethodTable[lockmethod] == INVALID_LOCKMETHOD)		return INVALID_LOCKMETHOD;	/* other modules refer to the lock table by a lockmethod */	newLockMethod = NumLockMethods;	NumLockMethods++;	LockMethodTable[newLockMethod] = LockMethodTable[lockmethod];	return newLockMethod;}/* * LockAcquire -- Check for lock conflicts, sleep if conflict found, *		set lock if/when no conflicts. * * Returns: TRUE if parameters are correct, FALSE otherwise. * * Side Effects: The lock is always acquired.  No way to abort *		a lock acquisition other than aborting the transaction. *		Lock is recorded in the lkchain. *#ifdef USER_LOCKS * * 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 use lock tags made of an uint16 and an uint32, for *		example 0 and a tuple oid, or any other arbitrary pair of *		numbers following a convention established by the application. *		In this sense tags don't refer to tuples or database entities. *		User locks and normal locks are completely orthogonal and *		they don't interfere with each other, so it is possible *		to acquire a normal lock on an user-locked tuple or user-lock *		a tuple for which a normal write lock already exists. *		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, and are distinguished from normal locks *		for the following differences: * *										normal lock		user lock * *		lockmethod						1				2 *		tag.relId						rel oid			0 *		tag.ItemPointerData.ip_blkid	block id		lock id2 *		tag.ItemPointerData.ip_posid	tuple offset	lock id1 *		xid.pid							0				backend pid *		xid.xid							xid or 0		0 *		persistence						transaction		user or backend * *		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#endif */boolLockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag, LOCKMODE lockmode){	XIDLookupEnt *result,				item;	HTAB	   *xidTable;	bool		found;	LOCK	   *lock = NULL;	SPINLOCK	masterLock;	LOCKMETHODTABLE *lockMethodTable;	int			status;	TransactionId xid;#ifdef USER_LOCKS	int			is_user_lock;	is_user_lock = (lockmethod == USER_LOCKMETHOD);	if (is_user_lock)	{#ifdef USER_LOCKS_DEBUG		TPRINTF(TRACE_USERLOCKS, "LockAcquire: user lock [%u] %s",				locktag->objId.blkno,				lock_types[lockmode]);#endif	}#endif	/* ???????? This must be changed when short term locks will be used */	locktag->lockmethod = lockmethod;	Assert(lockmethod < NumLockMethods);	lockMethodTable = LockMethodTable[lockmethod];	if (!lockMethodTable)	{		elog(NOTICE, "LockAcquire: bad lock table %d", lockmethod);		return FALSE;	}	if (LockingIsDisabled)		return TRUE;	masterLock = lockMethodTable->ctl->masterLock;	SpinAcquire(masterLock);	/*	 * Find or create a lock with this tag

⌨️ 快捷键说明

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