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

📄 lock.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 5 页
字号:
	LWLockAcquire(partitionLock, LW_EXCLUSIVE);	/*	 * We don't need to re-find the lock or proclock, since we kept their	 * addresses in the locallock table, and they couldn't have been removed	 * while we were holding a lock on them.	 */	lock = locallock->lock;	LOCK_PRINT("LockRelease: found", lock, lockmode);	proclock = locallock->proclock;	PROCLOCK_PRINT("LockRelease: found", proclock);	/*	 * Double-check that we are actually holding a lock of the type we want to	 * release.	 */	if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))	{		PROCLOCK_PRINT("LockRelease: WRONGTYPE", proclock);		LWLockRelease(partitionLock);		elog(WARNING, "you don't own a lock of type %s",			 lockMethodTable->lockModeNames[lockmode]);		RemoveLocalLock(locallock);		return FALSE;	}	/*	 * Do the releasing.  CleanUpLock will waken any now-wakable waiters.	 */	wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);	CleanUpLock(lock, proclock,				lockMethodTable, locallock->hashcode,				wakeupNeeded);	LWLockRelease(partitionLock);	RemoveLocalLock(locallock);	return TRUE;}/* * LockReleaseAll -- Release all locks of the specified lock method that *		are held by the current process. * * Well, not necessarily *all* locks.  The available behaviors are: *		allLocks == true: release all locks including session locks. *		allLocks == false: release all non-session locks. */voidLockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks){	HASH_SEQ_STATUS status;	LockMethod	lockMethodTable;	int			i,				numLockModes;	LOCALLOCK  *locallock;	LOCK	   *lock;	PROCLOCK   *proclock;	int			partition;	if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))		elog(ERROR, "unrecognized lock method: %d", lockmethodid);	lockMethodTable = LockMethods[lockmethodid];#ifdef LOCK_DEBUG	if (*(lockMethodTable->trace_flag))		elog(LOG, "LockReleaseAll: lockmethod=%d", lockmethodid);#endif	numLockModes = lockMethodTable->numLockModes;	/*	 * First we run through the locallock table and get rid of unwanted	 * entries, then we scan the process's proclocks and get rid of those. We	 * do this separately because we may have multiple locallock entries	 * pointing to the same proclock, and we daren't end up with any dangling	 * pointers.	 */	hash_seq_init(&status, LockMethodLocalHash);	while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)	{		if (locallock->proclock == NULL || locallock->lock == NULL)		{			/*			 * We must've run out of shared memory while trying to set up this			 * lock.  Just forget the local entry.			 */			Assert(locallock->nLocks == 0);			RemoveLocalLock(locallock);			continue;		}		/* Ignore items that are not of the lockmethod to be removed */		if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)			continue;		/*		 * If we are asked to release all locks, we can just zap the entry.		 * Otherwise, must scan to see if there are session locks. We assume		 * there is at most one lockOwners entry for session locks.		 */		if (!allLocks)		{			LOCALLOCKOWNER *lockOwners = locallock->lockOwners;			/* If it's above array position 0, move it down to 0 */			for (i = locallock->numLockOwners - 1; i > 0; i--)			{				if (lockOwners[i].owner == NULL)				{					lockOwners[0] = lockOwners[i];					break;				}			}			if (locallock->numLockOwners > 0 &&				lockOwners[0].owner == NULL &&				lockOwners[0].nLocks > 0)			{				/* Fix the locallock to show just the session locks */				locallock->nLocks = lockOwners[0].nLocks;				locallock->numLockOwners = 1;				/* We aren't deleting this locallock, so done */				continue;			}		}		/* Mark the proclock to show we need to release this lockmode */		if (locallock->nLocks > 0)			locallock->proclock->releaseMask |= LOCKBIT_ON(locallock->tag.mode);		/* And remove the locallock hashtable entry */		RemoveLocalLock(locallock);	}	/*	 * Now, scan each lock partition separately.	 */	for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)	{		LWLockId	partitionLock = FirstLockMgrLock + partition;		SHM_QUEUE  *procLocks = &(MyProc->myProcLocks[partition]);		proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,											 offsetof(PROCLOCK, procLink));		if (!proclock)			continue;			/* needn't examine this partition */		LWLockAcquire(partitionLock, LW_EXCLUSIVE);		while (proclock)		{			bool		wakeupNeeded = false;			PROCLOCK   *nextplock;			/* Get link first, since we may unlink/delete this proclock */			nextplock = (PROCLOCK *)				SHMQueueNext(procLocks, &proclock->procLink,							 offsetof(PROCLOCK, procLink));			Assert(proclock->tag.myProc == MyProc);			lock = proclock->tag.myLock;			/* Ignore items that are not of the lockmethod to be removed */			if (LOCK_LOCKMETHOD(*lock) != lockmethodid)				goto next_item;			/*			 * In allLocks mode, force release of all locks even if locallock			 * table had problems			 */			if (allLocks)				proclock->releaseMask = proclock->holdMask;			else				Assert((proclock->releaseMask & ~proclock->holdMask) == 0);			/*			 * Ignore items that have nothing to be released, unless they have			 * holdMask == 0 and are therefore recyclable			 */			if (proclock->releaseMask == 0 && proclock->holdMask != 0)				goto next_item;			PROCLOCK_PRINT("LockReleaseAll", proclock);			LOCK_PRINT("LockReleaseAll", lock, 0);			Assert(lock->nRequested >= 0);			Assert(lock->nGranted >= 0);			Assert(lock->nGranted <= lock->nRequested);			Assert((proclock->holdMask & ~lock->grantMask) == 0);			/*			 * Release the previously-marked lock modes			 */			for (i = 1; i <= numLockModes; i++)			{				if (proclock->releaseMask & LOCKBIT_ON(i))					wakeupNeeded |= UnGrantLock(lock, i, proclock,												lockMethodTable);			}			Assert((lock->nRequested >= 0) && (lock->nGranted >= 0));			Assert(lock->nGranted <= lock->nRequested);			LOCK_PRINT("LockReleaseAll: updated", lock, 0);			proclock->releaseMask = 0;			/* CleanUpLock will wake up waiters if needed. */			CleanUpLock(lock, proclock,						lockMethodTable,						LockTagHashCode(&lock->tag),						wakeupNeeded);	next_item:			proclock = nextplock;		}						/* loop over PROCLOCKs within this partition */		LWLockRelease(partitionLock);	}							/* loop over partitions */#ifdef LOCK_DEBUG	if (*(lockMethodTable->trace_flag))		elog(LOG, "LockReleaseAll done");#endif}/* * LockReleaseCurrentOwner *		Release all locks belonging to CurrentResourceOwner */voidLockReleaseCurrentOwner(void){	HASH_SEQ_STATUS status;	LOCALLOCK  *locallock;	LOCALLOCKOWNER *lockOwners;	int			i;	hash_seq_init(&status, LockMethodLocalHash);	while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)	{		/* Ignore items that must be nontransactional */		if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)			continue;		/* Scan to see if there are any locks belonging to current owner */		lockOwners = locallock->lockOwners;		for (i = locallock->numLockOwners - 1; i >= 0; i--)		{			if (lockOwners[i].owner == CurrentResourceOwner)			{				Assert(lockOwners[i].nLocks > 0);				if (lockOwners[i].nLocks < locallock->nLocks)				{					/*					 * We will still hold this lock after forgetting this					 * ResourceOwner.					 */					locallock->nLocks -= lockOwners[i].nLocks;					/* compact out unused slot */					locallock->numLockOwners--;					if (i < locallock->numLockOwners)						lockOwners[i] = lockOwners[locallock->numLockOwners];				}				else				{					Assert(lockOwners[i].nLocks == locallock->nLocks);					/* We want to call LockRelease just once */					lockOwners[i].nLocks = 1;					locallock->nLocks = 1;					if (!LockRelease(&locallock->tag.lock,									 locallock->tag.mode,									 false))						elog(WARNING, "LockReleaseCurrentOwner: failed??");				}				break;			}		}	}}/* * LockReassignCurrentOwner *		Reassign all locks belonging to CurrentResourceOwner to belong *		to its parent resource owner */voidLockReassignCurrentOwner(void){	ResourceOwner parent = ResourceOwnerGetParent(CurrentResourceOwner);	HASH_SEQ_STATUS status;	LOCALLOCK  *locallock;	LOCALLOCKOWNER *lockOwners;	Assert(parent != NULL);	hash_seq_init(&status, LockMethodLocalHash);	while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)	{		int			i;		int			ic = -1;		int			ip = -1;		/* Ignore items that must be nontransactional */		if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)			continue;		/*		 * Scan to see if there are any locks belonging to current owner or		 * its parent		 */		lockOwners = locallock->lockOwners;		for (i = locallock->numLockOwners - 1; i >= 0; i--)		{			if (lockOwners[i].owner == CurrentResourceOwner)				ic = i;			else if (lockOwners[i].owner == parent)				ip = i;		}		if (ic < 0)			continue;			/* no current locks */		if (ip < 0)		{			/* Parent has no slot, so just give it child's slot */			lockOwners[ic].owner = parent;		}		else		{			/* Merge child's count with parent's */			lockOwners[ip].nLocks += lockOwners[ic].nLocks;			/* compact out unused slot */			locallock->numLockOwners--;			if (ic < locallock->numLockOwners)				lockOwners[ic] = lockOwners[locallock->numLockOwners];		}	}}/* * GetLockConflicts *		Get an array of VirtualTransactionIds of xacts currently holding locks *		that would conflict with the specified lock/lockmode. *		xacts merely awaiting such a lock are NOT reported. * * The result array is palloc'd and is terminated with an invalid VXID. * * Of course, the result could be out of date by the time it's returned, * so use of this function has to be thought about carefully. * * Note we never include the current xact's vxid in the result array, * since an xact never blocks itself.  Also, prepared transactions are * ignored, which is a bit more debatable but is appropriate for current * uses of the result. */VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode){	VirtualTransactionId *vxids;	LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;	LockMethod	lockMethodTable;	LOCK	   *lock;	LOCKMASK	conflictMask;	SHM_QUEUE  *procLocks;	PROCLOCK   *proclock;	uint32		hashcode;	LWLockId	partitionLock;	int			count = 0;	if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))		elog(ERROR, "unrecognized lock method: %d", lockmethodid);	lockMethodTable = LockMethods[lockmethodid];	if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)		elog(ERROR, "unrecognized lock mode: %d", lockmode);	/*	 * Allocate memory to store results, and fill with InvalidVXID.  We only	 * need enough space for MaxBackends + a terminator, since prepared xacts	 * don't count.	 */	vxids = (VirtualTransactionId *)		palloc0(sizeof(VirtualTransactionId) * (MaxBackends + 1));	/*	 * Look up the lock object matching the tag.	 */	hashcode = LockTagHashCode(locktag);	partitionLock = LockHashPartitionLock(hashcode);	LWLockAcquire(partitionLock, LW_SHARED);	lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,												(void *) locktag,												hashcode,												HASH_FIND,												NULL);	if (!lock)	{		/*		 * If the lock object doesn't exist, there is nothing holding a lock		 * on this lockable object.		 */		LWLockRelease(partitionLock);		return vxids;	}	/*	 * Examine each existing holder (or awaiter) of the lock.	 */	conflictMask = lockMethodTable->conflictTab[lockmode];	procLocks = &(lock->procLocks);	proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,										 offsetof(PROCLOCK, lockLink));	while (proclock)	{		if (conflictMask & proclock->holdMask)		{			PGPROC	   *proc = proclock->tag.myProc;			/* A backend never blocks itself */			if (proc != MyProc)			{				VirtualTransactionId vxid;				GET_VXID_FROM_PGPROC(vxid, *proc);				/*				 * If we see an invalid VXID, then either the xact has already				 * committed (or aborted), or it's a prepared xact.  In either				 * case we may ignore it.				 */				if (VirtualTransactionIdIsValid(vxid))					vxids[count++] = vxid;			}		}		proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,											 offsetof(PROCLOCK, lockLink));	}	LWLockRelease(partitionLock);	if (count > MaxBackends)	/* should never happen */

⌨️ 快捷键说明

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