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

📄 procarray.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * procarray.c *	  POSTGRES process array code. * * * This module maintains an unsorted array of the PGPROC structures for all * active backends.  Although there are several uses for this, the principal * one is as a means of determining the set of currently running transactions. * * Because of various subtle race conditions it is critical that a backend * hold the correct locks while setting or clearing its MyProc->xid field. * See notes in src/backend/access/transam/README. * * The process array now also includes PGPROC structures representing * prepared transactions.  The xid and subxids fields of these are valid, * as are the myProcLocks lists.  They can be distinguished from regular * backend PGPROCs at need by checking for pid == 0. * * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.40 2008/01/09 21:52:36 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <signal.h>#include "access/subtrans.h"#include "access/transam.h"#include "access/xact.h"#include "access/twophase.h"#include "miscadmin.h"#include "storage/procarray.h"#include "utils/tqual.h"/* Our shared memory area */typedef struct ProcArrayStruct{	int			numProcs;		/* number of valid procs entries */	int			maxProcs;		/* allocated size of procs array */	/*	 * We declare procs[] as 1 entry because C wants a fixed-size array, but	 * actually it is maxProcs entries long.	 */	PGPROC	   *procs[1];		/* VARIABLE LENGTH ARRAY */} ProcArrayStruct;static ProcArrayStruct *procArray;#ifdef XIDCACHE_DEBUG/* counters for XidCache measurement */static long xc_by_recent_xmin = 0;static long xc_by_my_xact = 0;static long xc_by_latest_xid = 0;static long xc_by_main_xid = 0;static long xc_by_child_xid = 0;static long xc_no_overflow = 0;static long xc_slow_answer = 0;#define xc_by_recent_xmin_inc()		(xc_by_recent_xmin++)#define xc_by_my_xact_inc()			(xc_by_my_xact++)#define xc_by_latest_xid_inc()		(xc_by_latest_xid++)#define xc_by_main_xid_inc()		(xc_by_main_xid++)#define xc_by_child_xid_inc()		(xc_by_child_xid++)#define xc_no_overflow_inc()		(xc_no_overflow++)#define xc_slow_answer_inc()		(xc_slow_answer++)static void DisplayXidCache(void);#else							/* !XIDCACHE_DEBUG */#define xc_by_recent_xmin_inc()		((void) 0)#define xc_by_my_xact_inc()			((void) 0)#define xc_by_latest_xid_inc()		((void) 0)#define xc_by_main_xid_inc()		((void) 0)#define xc_by_child_xid_inc()		((void) 0)#define xc_no_overflow_inc()		((void) 0)#define xc_slow_answer_inc()		((void) 0)#endif   /* XIDCACHE_DEBUG *//* * Report shared-memory space needed by CreateSharedProcArray. */SizeProcArrayShmemSize(void){	Size		size;	size = offsetof(ProcArrayStruct, procs);	size = add_size(size, mul_size(sizeof(PGPROC *),								 add_size(MaxBackends, max_prepared_xacts)));	return size;}/* * Initialize the shared PGPROC array during postmaster startup. */voidCreateSharedProcArray(void){	bool		found;	/* Create or attach to the ProcArray shared structure */	procArray = (ProcArrayStruct *)		ShmemInitStruct("Proc Array", ProcArrayShmemSize(), &found);	if (!found)	{		/*		 * We're the first - initialize.		 */		procArray->numProcs = 0;		procArray->maxProcs = MaxBackends + max_prepared_xacts;	}}/* * Add the specified PGPROC to the shared array. */voidProcArrayAdd(PGPROC *proc){	ProcArrayStruct *arrayP = procArray;	LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);	if (arrayP->numProcs >= arrayP->maxProcs)	{		/*		 * Ooops, no room.	(This really shouldn't happen, since there is a		 * fixed supply of PGPROC structs too, and so we should have failed		 * earlier.)		 */		LWLockRelease(ProcArrayLock);		ereport(FATAL,				(errcode(ERRCODE_TOO_MANY_CONNECTIONS),				 errmsg("sorry, too many clients already")));	}	arrayP->procs[arrayP->numProcs] = proc;	arrayP->numProcs++;	LWLockRelease(ProcArrayLock);}/* * Remove the specified PGPROC from the shared array. * * When latestXid is a valid XID, we are removing a live 2PC gxact from the * array, and thus causing it to appear as "not running" anymore.  In this * case we must advance latestCompletedXid.  (This is essentially the same * as ProcArrayEndTransaction followed by removal of the PGPROC, but we take * the ProcArrayLock only once, and don't damage the content of the PGPROC; * twophase.c depends on the latter.) */voidProcArrayRemove(PGPROC *proc, TransactionId latestXid){	ProcArrayStruct *arrayP = procArray;	int			index;#ifdef XIDCACHE_DEBUG	/* dump stats at backend shutdown, but not prepared-xact end */	if (proc->pid != 0)		DisplayXidCache();#endif	LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);	if (TransactionIdIsValid(latestXid))	{		Assert(TransactionIdIsValid(proc->xid));		/* Advance global latestCompletedXid while holding the lock */		if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,								  latestXid))			ShmemVariableCache->latestCompletedXid = latestXid;	}	else	{		/* Shouldn't be trying to remove a live transaction here */		Assert(!TransactionIdIsValid(proc->xid));	}	for (index = 0; index < arrayP->numProcs; index++)	{		if (arrayP->procs[index] == proc)		{			arrayP->procs[index] = arrayP->procs[arrayP->numProcs - 1];			arrayP->numProcs--;			LWLockRelease(ProcArrayLock);			return;		}	}	/* Ooops */	LWLockRelease(ProcArrayLock);	elog(LOG, "failed to find proc %p in ProcArray", proc);}/* * ProcArrayEndTransaction -- mark a transaction as no longer running * * This is used interchangeably for commit and abort cases.  The transaction * commit/abort must already be reported to WAL and pg_clog. * * proc is currently always MyProc, but we pass it explicitly for flexibility. * latestXid is the latest Xid among the transaction's main XID and * subtransactions, or InvalidTransactionId if it has no XID.  (We must ask * the caller to pass latestXid, instead of computing it from the PGPROC's * contents, because the subxid information in the PGPROC might be * incomplete.) */voidProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid){	if (TransactionIdIsValid(latestXid))	{		/*		 * We must lock ProcArrayLock while clearing proc->xid, so that we do		 * not exit the set of "running" transactions while someone else is		 * taking a snapshot.  See discussion in		 * src/backend/access/transam/README.		 */		Assert(TransactionIdIsValid(proc->xid));		LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);		proc->xid = InvalidTransactionId;		proc->lxid = InvalidLocalTransactionId;		proc->xmin = InvalidTransactionId;		/* must be cleared with xid/xmin: */		proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;		proc->inCommit = false; /* be sure this is cleared in abort */		/* Clear the subtransaction-XID cache too while holding the lock */		proc->subxids.nxids = 0;		proc->subxids.overflowed = false;		/* Also advance global latestCompletedXid while holding the lock */		if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,								  latestXid))			ShmemVariableCache->latestCompletedXid = latestXid;		LWLockRelease(ProcArrayLock);	}	else	{		/*		 * If we have no XID, we don't need to lock, since we won't affect		 * anyone else's calculation of a snapshot.  We might change their		 * estimate of global xmin, but that's OK.		 */		Assert(!TransactionIdIsValid(proc->xid));		proc->lxid = InvalidLocalTransactionId;		proc->xmin = InvalidTransactionId;		/* must be cleared with xid/xmin: */		proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;		proc->inCommit = false; /* be sure this is cleared in abort */		Assert(proc->subxids.nxids == 0);		Assert(proc->subxids.overflowed == false);	}}/* * ProcArrayClearTransaction -- clear the transaction fields * * This is used after successfully preparing a 2-phase transaction.  We are * not actually reporting the transaction's XID as no longer running --- it * will still appear as running because the 2PC's gxact is in the ProcArray * too.  We just have to clear out our own PGPROC. */voidProcArrayClearTransaction(PGPROC *proc){	/*	 * We can skip locking ProcArrayLock here, because this action does not	 * actually change anyone's view of the set of running XIDs: our entry is	 * duplicate with the gxact that has already been inserted into the	 * ProcArray.	 */	proc->xid = InvalidTransactionId;	proc->lxid = InvalidLocalTransactionId;	proc->xmin = InvalidTransactionId;	/* redundant, but just in case */	proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;	proc->inCommit = false;	/* Clear the subtransaction-XID cache too */	proc->subxids.nxids = 0;	proc->subxids.overflowed = false;}/* * TransactionIdIsInProgress -- is given transaction running in some backend * * Aside from some shortcuts such as checking RecentXmin and our own Xid, * there are three possibilities for finding a running transaction: * * 1. the given Xid is a main transaction Id.  We will find this out cheaply * by looking at the PGPROC struct for each backend. * * 2. the given Xid is one of the cached subxact Xids in the PGPROC array. * We can find this out cheaply too. * * 3. Search the SubTrans tree to find the Xid's topmost parent, and then * see if that is running according to PGPROC.	This is the slowest, but * sadly it has to be done always if the other two failed, unless we see * that the cached subxact sets are complete (none have overflowed). * * ProcArrayLock has to be held while we do 1 and 2.  If we save the top Xids * while doing 1, we can release the ProcArrayLock while we do 3.  This buys * back some concurrency (we can't retrieve the main Xids from PGPROC again * anyway; see GetNewTransactionId). */boolTransactionIdIsInProgress(TransactionId xid){	static TransactionId *xids = NULL;	int			nxids = 0;	ProcArrayStruct *arrayP = procArray;	TransactionId topxid;	int			i,				j;	/*	 * Don't bother checking a transaction older than RecentXmin; it could not	 * possibly still be running.  (Note: in particular, this guarantees that	 * we reject InvalidTransactionId, FrozenTransactionId, etc as not	 * running.)	 */	if (TransactionIdPrecedes(xid, RecentXmin))	{		xc_by_recent_xmin_inc();		return false;	}	/*	 * Also, we can handle our own transaction (and subtransactions) without	 * any access to shared memory.	 */	if (TransactionIdIsCurrentTransactionId(xid))	{		xc_by_my_xact_inc();		return true;	}	/*	 * If not first time through, get workspace to remember main XIDs in. We	 * malloc it permanently to avoid repeated palloc/pfree overhead.	 */	if (xids == NULL)	{		xids = (TransactionId *)			malloc(arrayP->maxProcs * sizeof(TransactionId));		if (xids == NULL)			ereport(ERROR,					(errcode(ERRCODE_OUT_OF_MEMORY),					 errmsg("out of memory")));	}	LWLockAcquire(ProcArrayLock, LW_SHARED);	/*	 * Now that we have the lock, we can check latestCompletedXid; if the	 * target Xid is after that, it's surely still running.	 */	if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid, xid))	{		LWLockRelease(ProcArrayLock);		xc_by_latest_xid_inc();		return true;	}	/* No shortcuts, gotta grovel through the array */	for (i = 0; i < arrayP->numProcs; i++)	{		volatile PGPROC *proc = arrayP->procs[i];		TransactionId pxid;		/* Ignore my own proc --- dealt with it above */		if (proc == MyProc)			continue;		/* Fetch xid just once - see GetNewTransactionId */		pxid = proc->xid;		if (!TransactionIdIsValid(pxid))			continue;		/*		 * Step 1: check the main Xid		 */		if (TransactionIdEquals(pxid, xid))		{			LWLockRelease(ProcArrayLock);			xc_by_main_xid_inc();			return true;		}		/*		 * We can ignore main Xids that are younger than the target Xid, since		 * the target could not possibly be their child.		 */		if (TransactionIdPrecedes(xid, pxid))			continue;		/*		 * Step 2: check the cached child-Xids arrays		 */		for (j = proc->subxids.nxids - 1; j >= 0; j--)		{			/* Fetch xid just once - see GetNewTransactionId */			TransactionId cxid = proc->subxids.xids[j];			if (TransactionIdEquals(cxid, xid))			{				LWLockRelease(ProcArrayLock);				xc_by_child_xid_inc();				return true;			}		}		/*		 * Save the main Xid for step 3.  We only need to remember main Xids		 * that have uncached children.  (Note: there is no race condition		 * here because the overflowed flag cannot be cleared, only set, while		 * we hold ProcArrayLock.  So we can't miss an Xid that we need to		 * worry about.)		 */		if (proc->subxids.overflowed)			xids[nxids++] = pxid;

⌨️ 快捷键说明

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