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

📄 lock.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
	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);	}	LWLockAcquire(masterLock, LW_EXCLUSIVE);	proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,										 offsetof(PROCLOCK, procLink));	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.proc == MAKE_OFFSET(MyProc));		lock = (LOCK *) MAKE_PTR(proclock->tag.lock);		/* 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(lockmethodid, lock, proclock, wakeupNeeded);next_item:		proclock = nextplock;	}	LWLockRelease(masterLock);#ifdef LOCK_DEBUG	if (lockmethodid == USER_LOCKMETHOD ? Trace_userlocks : Trace_locks)		elog(LOG, "LockReleaseAll done");#endif}/* * LockReleaseCurrentOwner *		Release all locks belonging to CurrentResourceOwner * * Only DEFAULT_LOCKMETHOD locks can belong to a resource owner. */voidLockReleaseCurrentOwner(void){	HASH_SEQ_STATUS status;	LOCALLOCK  *locallock;	LOCALLOCKOWNER *lockOwners;	int			i;	hash_seq_init(&status, LockMethodLocalHash[DEFAULT_LOCKMETHOD]);	while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)	{		/* Ignore items that must be nontransactional */		if (LOCALLOCK_LOCKMETHOD(*locallock) != DEFAULT_LOCKMETHOD)			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(DEFAULT_LOCKMETHOD,									 &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[DEFAULT_LOCKMETHOD]);	while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)	{		int			i;		int			ic = -1;		int			ip = -1;		/* Ignore items that must be nontransactional */		if (LOCALLOCK_LOCKMETHOD(*locallock) != DEFAULT_LOCKMETHOD)			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];		}	}}/* * AtPrepare_Locks *		Do the preparatory work for a PREPARE: make 2PC state file records *		for all locks currently held. * * User locks are non-transactional and are therefore ignored. * * There are some special cases that we error out on: we can't be holding * any session locks (should be OK since only VACUUM uses those) and we * can't be holding any locks on temporary objects (since that would mess * up the current backend if it tries to exit before the prepared xact is * committed). */voidAtPrepare_Locks(void){	LOCKMETHODID lockmethodid = DEFAULT_LOCKMETHOD;	HASH_SEQ_STATUS status;	LOCALLOCK  *locallock;	/*	 * We don't need to touch shared memory for this --- all the necessary	 * state information is in the locallock table.	 */	hash_seq_init(&status, LockMethodLocalHash[lockmethodid]);	while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)	{		TwoPhaseLockRecord record;		LOCALLOCKOWNER *lockOwners = locallock->lockOwners;		int			i;		/* Ignore items that are not of the lockmethod to be processed */		if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)			continue;		/* Ignore it if we don't actually hold the lock */		if (locallock->nLocks <= 0)			continue;		/* Scan to verify there are no session locks */		for (i = locallock->numLockOwners - 1; i >= 0; i--)		{			/* elog not ereport since this should not happen */			if (lockOwners[i].owner == NULL)				elog(ERROR, "cannot PREPARE when session locks exist");		}		/* Can't handle it if the lock is on a temporary object */		if (locallock->isTempObject)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("cannot PREPARE a transaction that has operated on temporary tables")));		/*		 * Create a 2PC record.		 */		memcpy(&(record.locktag), &(locallock->tag.lock), sizeof(LOCKTAG));		record.lockmode = locallock->tag.mode;		RegisterTwoPhaseRecord(TWOPHASE_RM_LOCK_ID, 0,							   &record, sizeof(TwoPhaseLockRecord));	}}/* * PostPrepare_Locks *		Clean up after successful PREPARE * * Here, we want to transfer ownership of our locks to a dummy PGPROC * that's now associated with the prepared transaction, and we want to * clean out the corresponding entries in the LOCALLOCK table. * * Note: by removing the LOCALLOCK entries, we are leaving dangling * pointers in the transaction's resource owner.  This is OK at the * moment since resowner.c doesn't try to free locks retail at a toplevel * transaction commit or abort.  We could alternatively zero out nLocks * and leave the LOCALLOCK entries to be garbage-collected by LockReleaseAll, * but that probably costs more cycles. */voidPostPrepare_Locks(TransactionId xid){	PGPROC	   *newproc = TwoPhaseGetDummyProc(xid);	LOCKMETHODID lockmethodid = DEFAULT_LOCKMETHOD;	HASH_SEQ_STATUS status;	SHM_QUEUE  *procLocks = &(MyProc->procLocks);	LWLockId	masterLock;	LockMethod	lockMethodTable;	int			numLockModes;	LOCALLOCK  *locallock;	PROCLOCK   *proclock;	PROCLOCKTAG proclocktag;	bool		found;	LOCK	   *lock;	/* This is a critical section: any error means big trouble */	START_CRIT_SECTION();	lockMethodTable = LockMethods[lockmethodid];	if (!lockMethodTable)		elog(ERROR, "unrecognized lock method: %d", lockmethodid);	numLockModes = lockMethodTable->numLockModes;	masterLock = lockMethodTable->masterLock;	/*	 * First we run through the locallock table and get rid of unwanted	 * entries, then we scan the process's proclocks and transfer them to the	 * target proc.	 *	 * 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[lockmethodid]);	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;		/* We already checked there are no session locks */		/* 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);	}	LWLockAcquire(masterLock, LW_EXCLUSIVE);	proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,										 offsetof(PROCLOCK, procLink));	while (proclock)	{		PROCLOCK   *nextplock;		LOCKMASK	holdMask;		PROCLOCK   *newproclock;		/* Get link first, since we may unlink/delete this proclock */		nextplock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->procLink,											  offsetof(PROCLOCK, procLink));		Assert(proclock->tag.proc == MAKE_OFFSET(MyProc));		lock = (LOCK *) MAKE_PTR(proclock->tag.lock);		/* Ignore items that are not of the lockmethod to be removed */		if (LOCK_LOCKMETHOD(*lock) != lockmethodid)			goto next_item;		PROCLOCK_PRINT("PostPrepare_Locks", proclock);		LOCK_PRINT("PostPrepare_Locks", lock, 0);		Assert(lock->nRequested >= 0);		Assert(lock->nGranted >= 0);		Assert(lock->nGranted <= lock->nRequested);		Assert((proclock->holdMask & ~lock->grantMask) == 0);		/*		 * Since there were no session locks, we should be releasing all locks		 */		if (proclock->releaseMask != proclock->holdMask)			elog(PANIC, "we seem to have dropped a bit somewhere");		holdMask = proclock->holdMask;		/*		 * We cannot simply modify proclock->tag.proc to reassign ownership of		 * the lock, because that's part of the hash key and the proclock		 * would then be in the wrong hash chain.  So, unlink and delete the		 * old proclock; create a new one with the right contents; and link it		 * into place.	We do it in this order to be certain we won't run out		 * of shared memory (the way dynahash.c works, the deleted object is		 * certain to be available for reallocation).		 */		SHMQueueDelete(&proclock->lockLink);		SHMQueueDelete(&proclock->procLink);		if (!hash_search(LockMethodProcLockHash[lockmethodid],						 (void *) &(proclock->tag),						 HASH_REMOVE, NULL))			elog(PANIC, "proclock table corrupted");		/*		 * Create the hash key for the new proclock table.		 */

⌨️ 快捷键说明

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