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

📄 deadlock.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * deadlock.c *	  POSTGRES deadlock detection code * * See src/backend/storage/lmgr/README for a description of the deadlock * detection and resolution algorithms. * * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/deadlock.c,v 1.25 2003/09/25 06:58:02 petere Exp $ * *	Interface: * *	DeadLockCheck() *	DeadLockReport() *	RememberSimpleDeadLock() *	InitDeadLockChecking() * *------------------------------------------------------------------------- */#include "postgres.h"#include "lib/stringinfo.h"#include "miscadmin.h"#include "storage/proc.h"#include "utils/memutils.h"/* One edge in the waits-for graph */typedef struct{	PGPROC	   *waiter;			/* the waiting process */	PGPROC	   *blocker;		/* the process it is waiting for */	int			pred;			/* workspace for TopoSort */	int			link;			/* workspace for TopoSort */} EDGE;/* One potential reordering of a lock's wait queue */typedef struct{	LOCK	   *lock;			/* the lock whose wait queue is described */	PGPROC	  **procs;			/* array of PGPROC *'s in new wait order */	int			nProcs;} WAIT_ORDER;/* * Information saved about each edge in a detected deadlock cycle.	This * is used to print a diagnostic message upon failure. * * Note: because we want to examine this info after releasing the LockMgrLock, * we can't just store LOCK and PGPROC pointers; we must extract out all the * info we want to be able to print. */typedef struct{	LOCKTAG		locktag;		/* ID of awaited lock object */	LOCKMODE	lockmode;		/* type of lock we're waiting for */	int			pid;			/* PID of blocked backend */} DEADLOCK_INFO;static bool DeadLockCheckRecurse(PGPROC *proc);static int	TestConfiguration(PGPROC *startProc);static bool FindLockCycle(PGPROC *checkProc,			  EDGE *softEdges, int *nSoftEdges);static bool FindLockCycleRecurse(PGPROC *checkProc, int depth,					 EDGE *softEdges, int *nSoftEdges);static bool ExpandConstraints(EDGE *constraints, int nConstraints);static bool TopoSort(LOCK *lock, EDGE *constraints, int nConstraints,		 PGPROC **ordering);#ifdef DEBUG_DEADLOCKstatic void PrintLockQueue(LOCK *lock, const char *info);#endif/* * Working space for the deadlock detector *//* Workspace for FindLockCycle */static PGPROC **visitedProcs;	/* Array of visited procs */static int	nVisitedProcs;/* Workspace for TopoSort */static PGPROC **topoProcs;		/* Array of not-yet-output procs */static int *beforeConstraints;	/* Counts of remaining before-constraints */static int *afterConstraints;	/* List head for after-constraints *//* Output area for ExpandConstraints */static WAIT_ORDER *waitOrders;	/* Array of proposed queue rearrangements */static int	nWaitOrders;static PGPROC **waitOrderProcs; /* Space for waitOrders queue contents *//* Current list of constraints being considered */static EDGE *curConstraints;static int	nCurConstraints;static int	maxCurConstraints;/* Storage space for results from FindLockCycle */static EDGE *possibleConstraints;static int	nPossibleConstraints;static int	maxPossibleConstraints;static DEADLOCK_INFO *deadlockDetails;static int	nDeadlockDetails;/* * InitDeadLockChecking -- initialize deadlock checker during backend startup * * This does per-backend initialization of the deadlock checker; primarily, * allocation of working memory for DeadLockCheck.	We do this per-backend * since there's no percentage in making the kernel do copy-on-write * inheritance of workspace from the postmaster.  We want to allocate the * space at startup because the deadlock checker might be invoked when there's * no free memory left. */voidInitDeadLockChecking(void){	MemoryContext oldcxt;	/* Make sure allocations are permanent */	oldcxt = MemoryContextSwitchTo(TopMemoryContext);	/*	 * FindLockCycle needs at most MaxBackends entries in visitedProcs[]	 * and deadlockDetails[].	 */	visitedProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));	deadlockDetails = (DEADLOCK_INFO *) palloc(MaxBackends * sizeof(DEADLOCK_INFO));	/*	 * TopoSort needs to consider at most MaxBackends wait-queue entries,	 * and it needn't run concurrently with FindLockCycle.	 */	topoProcs = visitedProcs;	/* re-use this space */	beforeConstraints = (int *) palloc(MaxBackends * sizeof(int));	afterConstraints = (int *) palloc(MaxBackends * sizeof(int));	/*	 * We need to consider rearranging at most MaxBackends/2 wait queues	 * (since it takes at least two waiters in a queue to create a soft	 * edge), and the expanded form of the wait queues can't involve more	 * than MaxBackends total waiters.	(But avoid palloc(0) if	 * MaxBackends = 1.)	 */	waitOrders = (WAIT_ORDER *)		palloc(((MaxBackends + 1) / 2) * sizeof(WAIT_ORDER));	waitOrderProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));	/*	 * Allow at most MaxBackends distinct constraints in a configuration.	 * (Is this enough?  In practice it seems it should be, but I don't	 * quite see how to prove it.  If we run out, we might fail to find a	 * workable wait queue rearrangement even though one exists.)  NOTE	 * that this number limits the maximum recursion depth of	 * DeadLockCheckRecurse. Making it really big might potentially allow	 * a stack-overflow problem.	 */	maxCurConstraints = MaxBackends;	curConstraints = (EDGE *) palloc(maxCurConstraints * sizeof(EDGE));	/*	 * Allow up to 3*MaxBackends constraints to be saved without having to	 * re-run TestConfiguration.  (This is probably more than enough, but	 * we can survive if we run low on space by doing excess runs of	 * TestConfiguration to re-compute constraint lists each time needed.)	 * The last MaxBackends entries in possibleConstraints[] are reserved	 * as output workspace for FindLockCycle.	 */	maxPossibleConstraints = MaxBackends * 4;	possibleConstraints =		(EDGE *) palloc(maxPossibleConstraints * sizeof(EDGE));	MemoryContextSwitchTo(oldcxt);}/* * DeadLockCheck -- Checks for deadlocks for a given process * * This code looks for deadlocks involving the given process.  If any * are found, it tries to rearrange lock wait queues to resolve the * deadlock.  If resolution is impossible, return TRUE --- the caller * is then expected to abort the given proc's transaction. * * We can't block on user locks, so no sense testing for deadlock * because there is no blocking, and no timer for the block.  So, * only look at regular locks. * * We must have already locked the master lock before being called. * NOTE: although the lockmethod structure appears to allow each lock * table to have a different masterLock, all locks that can block had * better use the same LWLock, else this code will not be adequately * interlocked! * * On failure, deadlock details are recorded in deadlockDetails[] for * subsequent printing by DeadLockReport().  That activity is separate * because we don't want to do it while holding the master lock. */boolDeadLockCheck(PGPROC *proc){	int			i,				j;	/* Initialize to "no constraints" */	nCurConstraints = 0;	nPossibleConstraints = 0;	nWaitOrders = 0;	/* Search for deadlocks and possible fixes */	if (DeadLockCheckRecurse(proc))	{		/*		 * Call FindLockCycle one more time, to record the correct		 * deadlockDetails[] for the basic state with no rearrangements.		 */		int			nSoftEdges;		nWaitOrders = 0;		if (!FindLockCycle(proc, possibleConstraints, &nSoftEdges))			elog(FATAL, "deadlock seems to have disappeared");		return true;			/* cannot find a non-deadlocked state */	}	/* Apply any needed rearrangements of wait queues */	for (i = 0; i < nWaitOrders; i++)	{		LOCK	   *lock = waitOrders[i].lock;		PGPROC	  **procs = waitOrders[i].procs;		int			nProcs = waitOrders[i].nProcs;		PROC_QUEUE *waitQueue = &(lock->waitProcs);		Assert(nProcs == waitQueue->size);#ifdef DEBUG_DEADLOCK		PrintLockQueue(lock, "DeadLockCheck:");#endif		/* Reset the queue and re-add procs in the desired order */		ProcQueueInit(waitQueue);		for (j = 0; j < nProcs; j++)		{			SHMQueueInsertBefore(&(waitQueue->links), &(procs[j]->links));			waitQueue->size++;		}#ifdef DEBUG_DEADLOCK		PrintLockQueue(lock, "rearranged to:");#endif		/* See if any waiters for the lock can be woken up now */		ProcLockWakeup(GetLocksMethodTable(lock), lock);	}	return false;}/* * DeadLockCheckRecurse -- recursively search for valid orderings * * curConstraints[] holds the current set of constraints being considered * by an outer level of recursion.	Add to this each possible solution * constraint for any cycle detected at this level. * * Returns TRUE if no solution exists.	Returns FALSE if a deadlock-free * state is attainable, in which case waitOrders[] shows the required * rearrangements of lock wait queues (if any). */static boolDeadLockCheckRecurse(PGPROC *proc){	int			nEdges;	int			oldPossibleConstraints;	bool		savedList;	int			i;	nEdges = TestConfiguration(proc);	if (nEdges < 0)		return true;			/* hard deadlock --- no solution */	if (nEdges == 0)		return false;			/* good configuration found */	if (nCurConstraints >= maxCurConstraints)		return true;			/* out of room for active constraints? */	oldPossibleConstraints = nPossibleConstraints;	if (nPossibleConstraints + nEdges + MaxBackends <= maxPossibleConstraints)	{		/* We can save the edge list in possibleConstraints[] */		nPossibleConstraints += nEdges;		savedList = true;	}	else	{		/* Not room; will need to regenerate the edges on-the-fly */		savedList = false;	}	/*	 * Try each available soft edge as an addition to the configuration.	 */	for (i = 0; i < nEdges; i++)	{		if (!savedList && i > 0)		{			/* Regenerate the list of possible added constraints */			if (nEdges != TestConfiguration(proc))				elog(FATAL, "inconsistent results during deadlock check");		}		curConstraints[nCurConstraints] =			possibleConstraints[oldPossibleConstraints + i];		nCurConstraints++;		if (!DeadLockCheckRecurse(proc))			return false;		/* found a valid solution! */		/* give up on that added constraint, try again */		nCurConstraints--;	}	nPossibleConstraints = oldPossibleConstraints;	return true;				/* no solution found */}/*-------------------- * Test a configuration (current set of constraints) for validity. * * Returns: *		0: the configuration is good (no deadlocks) *	   -1: the configuration has a hard deadlock or is not self-consistent *		>0: the configuration has one or more soft deadlocks * * In the soft-deadlock case, one of the soft cycles is chosen arbitrarily * and a list of its soft edges is returned beginning at * possibleConstraints+nPossibleConstraints.  The return value is the * number of soft edges. *-------------------- */static intTestConfiguration(PGPROC *startProc){	int			softFound = 0;	EDGE	   *softEdges = possibleConstraints + nPossibleConstraints;	int			nSoftEdges;	int			i;	/*	 * Make sure we have room for FindLockCycle's output.	 */	if (nPossibleConstraints + MaxBackends > maxPossibleConstraints)		return -1;	/*	 * Expand current constraint set into wait orderings.  Fail if the	 * constraint set is not self-consistent.	 */	if (!ExpandConstraints(curConstraints, nCurConstraints))		return -1;	/*	 * Check for cycles involving startProc or any of the procs mentioned	 * in constraints.	We check startProc last because if it has a soft	 * cycle still to be dealt with, we want to deal with that first.	 */	for (i = 0; i < nCurConstraints; i++)	{		if (FindLockCycle(curConstraints[i].waiter, softEdges, &nSoftEdges))		{			if (nSoftEdges == 0)				return -1;		/* hard deadlock detected */			softFound = nSoftEdges;		}		if (FindLockCycle(curConstraints[i].blocker, softEdges, &nSoftEdges))		{			if (nSoftEdges == 0)				return -1;		/* hard deadlock detected */			softFound = nSoftEdges;		}	}	if (FindLockCycle(startProc, softEdges, &nSoftEdges))	{		if (nSoftEdges == 0)			return -1;			/* hard deadlock detected */		softFound = nSoftEdges;	}	return softFound;}/* * FindLockCycle -- basic check for deadlock cycles * * Scan outward from the given proc to see if there is a cycle in the * waits-for graph that includes this proc.  Return TRUE if a cycle * is found, else FALSE.  If a cycle is found, we return a list of * the "soft edges", if any, included in the cycle.  These edges could * potentially be eliminated by rearranging wait queues.  We also fill * deadlockDetails[] with information about the detected cycle; this info * is not used by the deadlock algorithm itself, only to print a useful * message after failing. * * Since we need to be able to check hypothetical configurations that would * exist after wait queue rearrangement, the routine pays attention to the * table of hypothetical queue orders in waitOrders[].	These orders will * be believed in preference to the actual ordering seen in the locktable. */static boolFindLockCycle(PGPROC *checkProc,			  EDGE *softEdges,	/* output argument */			  int *nSoftEdges)	/* output argument */{	nVisitedProcs = 0;	nDeadlockDetails = 0;	*nSoftEdges = 0;	return FindLockCycleRecurse(checkProc, 0, softEdges, nSoftEdges);}static boolFindLockCycleRecurse(PGPROC *checkProc,					 int depth,					 EDGE *softEdges,	/* output argument */					 int *nSoftEdges)	/* output argument */{	PGPROC	   *proc;	LOCK	   *lock;	PROCLOCK   *proclock;	SHM_QUEUE  *lockHolders;	LOCKMETHODTABLE *lockMethodTable;	PROC_QUEUE *waitQueue;	int			queue_size;	int			conflictMask;	int			i;	int			numLockModes,				lm;	/*	 * Have we already seen this proc?	 */	for (i = 0; i < nVisitedProcs; i++)	{		if (visitedProcs[i] == checkProc)		{			/* If we return to starting point, we have a deadlock cycle */			if (i == 0)			{				/*				 * record total length of cycle --- outer levels will now				 * fill deadlockDetails[]				 */				Assert(depth <= MaxBackends);				nDeadlockDetails = depth;				return true;			}

⌨️ 快捷键说明

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