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

📄 lock.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
	Assert(lock->nGranted <= lock->nRequested);	/*	 * fix the general lock stats	 */	lock->nRequested--;	lock->requested[lockmode]--;	lock->nGranted--;	lock->granted[lockmode]--;	if (lock->granted[lockmode] == 0)	{		/* change the conflict mask.  No more of this lock type. */		lock->grantMask &= LOCKBIT_OFF(lockmode);	}	LOCK_PRINT("UnGrantLock: updated", lock, lockmode);	/*	 * We need only run ProcLockWakeup if the released lock conflicts with at	 * least one of the lock types requested by waiter(s).	Otherwise whatever	 * conflict made them wait must still exist.  NOTE: before MVCC, we could	 * skip wakeup if lock->granted[lockmode] was still positive. But that's	 * not true anymore, because the remaining granted locks might belong to	 * some waiter, who could now be awakened because he doesn't conflict with	 * his own locks.	 */	if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)		wakeupNeeded = true;	/*	 * Now fix the per-proclock state.	 */	proclock->holdMask &= LOCKBIT_OFF(lockmode);	PROCLOCK_PRINT("UnGrantLock: updated", proclock);	return wakeupNeeded;}/* * CleanUpLock -- clean up after releasing a lock.	We garbage-collect the * proclock and lock objects if possible, and call ProcLockWakeup if there * are remaining requests and the caller says it's OK.  (Normally, this * should be called after UnGrantLock, and wakeupNeeded is the result from * UnGrantLock.) * * The locktable's masterLock must be held at entry, and will be * held at exit. */static voidCleanUpLock(LOCKMETHODID lockmethodid, LOCK *lock, PROCLOCK *proclock,			bool wakeupNeeded){	/*	 * If this was my last hold on this lock, delete my entry in the proclock	 * table.	 */	if (proclock->holdMask == 0)	{		PROCLOCK_PRINT("CleanUpLock: deleting", proclock);		SHMQueueDelete(&proclock->lockLink);		SHMQueueDelete(&proclock->procLink);		if (!hash_search(LockMethodProcLockHash[lockmethodid],						 (void *) &(proclock->tag),						 HASH_REMOVE, NULL))			elog(PANIC, "proclock table corrupted");	}	if (lock->nRequested == 0)	{		/*		 * The caller just released the last lock, so garbage-collect the lock		 * object.		 */		LOCK_PRINT("CleanUpLock: deleting", lock, 0);		Assert(SHMQueueEmpty(&(lock->procLocks)));		if (!hash_search(LockMethodLockHash[lockmethodid],						 (void *) &(lock->tag),						 HASH_REMOVE, NULL))			elog(PANIC, "lock table corrupted");	}	else if (wakeupNeeded)	{		/* There are waiters on this lock, so wake them up. */		ProcLockWakeup(LockMethods[lockmethodid], lock);	}}/* * GrantLockLocal -- update the locallock data structures to show *		the lock request has been granted. * * We expect that LockAcquire made sure there is room to add a new * ResourceOwner entry. */static voidGrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner){	LOCALLOCKOWNER *lockOwners = locallock->lockOwners;	int			i;	Assert(locallock->numLockOwners < locallock->maxLockOwners);	/* Count the total */	locallock->nLocks++;	/* Count the per-owner lock */	for (i = 0; i < locallock->numLockOwners; i++)	{		if (lockOwners[i].owner == owner)		{			lockOwners[i].nLocks++;			return;		}	}	lockOwners[i].owner = owner;	lockOwners[i].nLocks = 1;	locallock->numLockOwners++;}/* * GrantAwaitedLock -- call GrantLockLocal for the lock we are doing *		WaitOnLock on. * * proc.c needs this for the case where we are booted off the lock by * timeout, but discover that someone granted us the lock anyway. * * We could just export GrantLockLocal, but that would require including * resowner.h in lock.h, which creates circularity. */voidGrantAwaitedLock(void){	GrantLockLocal(awaitedLock, awaitedOwner);}/* * WaitOnLock -- wait to acquire a lock * * Caller must have set MyProc->heldLocks to reflect locks already held * on the lockable object by this process. * * The locktable's masterLock must be held at entry. */static voidWaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,		   ResourceOwner owner){	LockMethod	lockMethodTable = LockMethods[lockmethodid];	const char *old_status;	char	   *new_status;	int			len;	Assert(lockmethodid < NumLockMethods);	LOCK_PRINT("WaitOnLock: sleeping on lock",			   locallock->lock, locallock->tag.mode);	old_status = get_ps_display(&len);	new_status = (char *) palloc(len + 8 + 1);	memcpy(new_status, old_status, len);	strcpy(new_status + len, " waiting");	set_ps_display(new_status);	new_status[len] = '\0';		/* truncate off " waiting" */	awaitedLock = locallock;	awaitedOwner = owner;	/*	 * NOTE: Think not to put any shared-state cleanup after the call to	 * ProcSleep, in either the normal or failure path.  The lock state must	 * be fully set by the lock grantor, or by CheckDeadLock if we give up	 * waiting for the lock.  This is necessary because of the possibility	 * that a cancel/die interrupt will interrupt ProcSleep after someone else	 * grants us the lock, but before we've noticed it. Hence, after granting,	 * the locktable state must fully reflect the fact that we own the lock;	 * we can't do additional work on return. Contrariwise, if we fail, any	 * cleanup must happen in xact abort processing, not here, to ensure it	 * will also happen in the cancel/die case.	 */	if (ProcSleep(lockMethodTable,				  locallock->tag.mode,				  locallock->lock,				  locallock->proclock) != STATUS_OK)	{		/*		 * We failed as a result of a deadlock, see CheckDeadLock(). Quit now.		 */		awaitedLock = NULL;		LOCK_PRINT("WaitOnLock: aborting on lock",				   locallock->lock, locallock->tag.mode);		LWLockRelease(lockMethodTable->masterLock);		/*		 * Now that we aren't holding the LockMgrLock, we can give an error		 * report including details about the detected deadlock.		 */		DeadLockReport();		/* not reached */	}	awaitedLock = NULL;	set_ps_display(new_status);	pfree(new_status);	LOCK_PRINT("WaitOnLock: wakeup on lock",			   locallock->lock, locallock->tag.mode);}/* * Remove a proc from the wait-queue it is on * (caller must know it is on one). * * Locktable lock must be held by caller. * * NB: this does not clean up any locallock object that may exist for the lock. */voidRemoveFromWaitQueue(PGPROC *proc){	LOCK	   *waitLock = proc->waitLock;	PROCLOCK   *proclock = proc->waitProcLock;	LOCKMODE	lockmode = proc->waitLockMode;	LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*waitLock);	/* Make sure proc is waiting */	Assert(proc->links.next != INVALID_OFFSET);	Assert(waitLock);	Assert(waitLock->waitProcs.size > 0);	Assert(0 < lockmethodid && lockmethodid < NumLockMethods);	/* Remove proc from lock's wait queue */	SHMQueueDelete(&(proc->links));	waitLock->waitProcs.size--;	/* Undo increments of request counts by waiting process */	Assert(waitLock->nRequested > 0);	Assert(waitLock->nRequested > proc->waitLock->nGranted);	waitLock->nRequested--;	Assert(waitLock->requested[lockmode] > 0);	waitLock->requested[lockmode]--;	/* don't forget to clear waitMask bit if appropriate */	if (waitLock->granted[lockmode] == waitLock->requested[lockmode])		waitLock->waitMask &= LOCKBIT_OFF(lockmode);	/* Clean up the proc's own state */	proc->waitLock = NULL;	proc->waitProcLock = NULL;	/*	 * Delete the proclock immediately if it represents no already-held locks.	 * (This must happen now because if the owner of the lock decides to	 * release it, and the requested/granted counts then go to zero,	 * LockRelease expects there to be no remaining proclocks.) Then see if	 * any other waiters for the lock can be woken up now.	 */	CleanUpLock(lockmethodid, waitLock, proclock, true);}/* * LockRelease -- look up 'locktag' in lock table 'lockmethodid' and *		release one 'lockmode' lock on it.	Release a session lock if *		'sessionLock' is true, else release a regular transaction lock. * * Side Effects: find any waiting processes that are now wakable, *		grant them their requested locks and awaken them. *		(We have to grant the lock here to avoid a race between *		the waking process and any new process to *		come along and request the lock.) */boolLockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,			LOCKMODE lockmode, bool sessionLock){	LOCALLOCKTAG localtag;	LOCALLOCK  *locallock;	LOCK	   *lock;	PROCLOCK   *proclock;	LWLockId	masterLock;	LockMethod	lockMethodTable;	bool		wakeupNeeded;#ifdef LOCK_DEBUG	if (Trace_userlocks && lockmethodid == USER_LOCKMETHOD)		elog(LOG, "LockRelease: user lock [%u,%u] %s",			 locktag->locktag_field1, locktag->locktag_field2,			 lock_mode_names[lockmode]);#endif	/* ugly */	locktag->locktag_lockmethodid = lockmethodid;	Assert(lockmethodid < NumLockMethods);	lockMethodTable = LockMethods[lockmethodid];	if (!lockMethodTable)		elog(ERROR, "unrecognized lock method: %d", lockmethodid);	/*	 * Find the LOCALLOCK entry for this lock and lockmode	 */	MemSet(&localtag, 0, sizeof(localtag));		/* must clear padding */	localtag.lock = *locktag;	localtag.mode = lockmode;	locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash[lockmethodid],										  (void *) &localtag,										  HASH_FIND, NULL);	/*	 * let the caller print its own error message, too. Do not ereport(ERROR).	 */	if (!locallock || locallock->nLocks <= 0)	{		elog(WARNING, "you don't own a lock of type %s",			 lock_mode_names[lockmode]);		return FALSE;	}	/*	 * Decrease the count for the resource owner.	 */	{		LOCALLOCKOWNER *lockOwners = locallock->lockOwners;		ResourceOwner owner;		int			i;		/* Session locks and user locks are not transactional */		if (!sessionLock && lockmethodid == DEFAULT_LOCKMETHOD)			owner = CurrentResourceOwner;		else			owner = NULL;		for (i = locallock->numLockOwners - 1; i >= 0; i--)		{			if (lockOwners[i].owner == owner)			{				Assert(lockOwners[i].nLocks > 0);				if (--lockOwners[i].nLocks == 0)				{					/* compact out unused slot */					locallock->numLockOwners--;					if (i < locallock->numLockOwners)						lockOwners[i] = lockOwners[locallock->numLockOwners];				}				break;			}		}		if (i < 0)		{			/* don't release a lock belonging to another owner */			elog(WARNING, "you don't own a lock of type %s",				 lock_mode_names[lockmode]);			return FALSE;		}	}	/*	 * Decrease the total local count.	If we're still holding the lock, we're	 * done.	 */	locallock->nLocks--;	if (locallock->nLocks > 0)		return TRUE;	/*	 * Otherwise we've got to mess with the shared lock table.	 */	masterLock = lockMethodTable->masterLock;	LWLockAcquire(masterLock, 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(masterLock);		elog(WARNING, "you don't own a lock of type %s",			 lock_mode_names[lockmode]);		RemoveLocalLock(locallock);		return FALSE;	}	/*	 * Do the releasing.  CleanUpLock will waken any now-wakable waiters.	 */	wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);	CleanUpLock(lockmethodid, lock, proclock, wakeupNeeded);	LWLockRelease(masterLock);	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;	SHM_QUEUE  *procLocks = &(MyProc->procLocks);	LWLockId	masterLock;	LockMethod	lockMethodTable;	int			i,				numLockModes;	LOCALLOCK  *locallock;	PROCLOCK   *proclock;	LOCK	   *lock;#ifdef LOCK_DEBUG	if (lockmethodid == USER_LOCKMETHOD ? Trace_userlocks : Trace_locks)		elog(LOG, "LockReleaseAll: lockmethod=%d", lockmethodid);#endif	Assert(lockmethodid < NumLockMethods);	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 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[lockmethodid]);

⌨️ 快捷键说明

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