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

📄 procarray.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * 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 GetSnapshotData. * * The process array now also includes PGPROC structures representing * prepared transactions.  The xid and subxids fields of these are valid, * as is the procLocks list.  They can be distinguished from regular backend * PGPROCs at need by checking for pid == 0. * * * Portions Copyright (c) 1996-2005, 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.7.2.1 2005/11/22 18:23:18 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/subtrans.h"#include "access/twophase.h"#include "miscadmin.h"#include "storage/proc.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_main_xid = 0;static long xc_by_child_xid = 0;static long xc_slow_answer = 0;#define xc_by_recent_xmin_inc()		(xc_by_recent_xmin++)#define xc_by_main_xid_inc()		(xc_by_main_xid++)#define xc_by_child_xid_inc()		(xc_by_child_xid++)#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_main_xid_inc()		((void) 0)#define xc_by_child_xid_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. */voidProcArrayRemove(PGPROC *proc){	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);	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);}/* * TransactionIdIsInProgress -- is given transaction running in some backend * * 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){	bool		result = false;	ProcArrayStruct *arrayP = procArray;	int			i,				j;	int			nxids = 0;	TransactionId *xids;	TransactionId topxid;	bool		locked;	/*	 * Don't bother checking a transaction older than RecentXmin; it could not	 * possibly still be running.	 */	if (TransactionIdPrecedes(xid, RecentXmin))	{		xc_by_recent_xmin_inc();		return false;	}	/* Get workspace to remember main XIDs in */	xids = (TransactionId *) palloc(sizeof(TransactionId) * arrayP->maxProcs);	LWLockAcquire(ProcArrayLock, LW_SHARED);	locked = true;	for (i = 0; i < arrayP->numProcs; i++)	{		PGPROC	   *proc = arrayP->procs[i];		/* Fetch xid just once - see GetNewTransactionId */		TransactionId pxid = proc->xid;		if (!TransactionIdIsValid(pxid))			continue;		/*		 * Step 1: check the main Xid		 */		if (TransactionIdEquals(pxid, xid))		{			xc_by_main_xid_inc();			result = true;			goto result_known;		}		/*		 * 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))			{				xc_by_child_xid_inc();				result = true;				goto result_known;			}		}		/*		 * 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;	}	LWLockRelease(ProcArrayLock);	locked = false;	/*	 * If none of the relevant caches overflowed, we know the Xid is not	 * running without looking at pg_subtrans.	 */	if (nxids == 0)		goto result_known;	/*	 * Step 3: have to check pg_subtrans.	 *	 * At this point, we know it's either a subtransaction of one of the Xids	 * in xids[], or it's not running.  If it's an already-failed	 * subtransaction, we want to say "not running" even though its parent may	 * still be running.  So first, check pg_clog to see if it's been aborted.	 */	xc_slow_answer_inc();	if (TransactionIdDidAbort(xid))		goto result_known;	/*	 * It isn't aborted, so check whether the transaction tree it belongs to	 * is still running (or, more precisely, whether it was running when this	 * routine started -- note that we already released ProcArrayLock).	 */	topxid = SubTransGetTopmostTransaction(xid);	Assert(TransactionIdIsValid(topxid));	if (!TransactionIdEquals(topxid, xid))	{		for (i = 0; i < nxids; i++)		{			if (TransactionIdEquals(xids[i], topxid))			{				result = true;				break;			}		}	}result_known:	if (locked)		LWLockRelease(ProcArrayLock);	pfree(xids);	return result;}/* * TransactionIdIsActive -- is xid the top-level XID of an active backend? * * This differs from TransactionIdIsInProgress in that it ignores prepared * transactions.  Also, we ignore subtransactions since that's not needed * for current uses. */boolTransactionIdIsActive(TransactionId xid){	bool		result = false;	ProcArrayStruct *arrayP = procArray;	int			i;	/*	 * Don't bother checking a transaction older than RecentXmin; it could not	 * possibly still be running.	 */	if (TransactionIdPrecedes(xid, RecentXmin))		return false;	LWLockAcquire(ProcArrayLock, LW_SHARED);	for (i = 0; i < arrayP->numProcs; i++)	{		PGPROC	   *proc = arrayP->procs[i];		/* Fetch xid just once - see GetNewTransactionId */		TransactionId pxid = proc->xid;		if (!TransactionIdIsValid(pxid))			continue;		if (proc->pid == 0)			continue;			/* ignore prepared transactions */		if (TransactionIdEquals(pxid, xid))		{			result = true;			break;		}	}	LWLockRelease(ProcArrayLock);	return result;}/* * GetOldestXmin -- returns oldest transaction that was running *					when any current transaction was started. * * If allDbs is TRUE then all backends are considered; if allDbs is FALSE * then only backends running in my own database are considered. * * This is used by VACUUM to decide which deleted tuples must be preserved * in a table.	allDbs = TRUE is needed for shared relations, but allDbs = * FALSE is sufficient for non-shared relations, since only backends in my * own database could ever see the tuples in them. * * This is also used to determine where to truncate pg_subtrans.  allDbs * must be TRUE for that case. * * Note: we include the currently running xids in the set of considered xids. * This ensures that if a just-started xact has not yet set its snapshot, * when it does set the snapshot it cannot set xmin less than what we compute. */TransactionIdGetOldestXmin(bool allDbs){	ProcArrayStruct *arrayP = procArray;	TransactionId result;	int			index;	/*	 * Normally we start the min() calculation with our own XID.  But if	 * called by checkpointer, we will not be inside a transaction, so use	 * next XID as starting point for min() calculation.  (Note that if there	 * are no xacts running at all, that will be the subtrans truncation	 * point!)	 */	if (IsTransactionState())		result = GetTopTransactionId();	else		result = ReadNewTransactionId();	LWLockAcquire(ProcArrayLock, LW_SHARED);	for (index = 0; index < arrayP->numProcs; index++)	{		PGPROC	   *proc = arrayP->procs[index];		if (allDbs || proc->databaseId == MyDatabaseId)		{			/* Fetch xid just once - see GetNewTransactionId */			TransactionId xid = proc->xid;			if (TransactionIdIsNormal(xid))			{				if (TransactionIdPrecedes(xid, result))					result = xid;				xid = proc->xmin;				if (TransactionIdIsNormal(xid))					if (TransactionIdPrecedes(xid, result))						result = xid;			}		}	}	LWLockRelease(ProcArrayLock);	return result;}/*---------- * GetSnapshotData -- returns information about running transactions. * * The returned snapshot includes xmin (lowest still-running xact ID), * xmax (next xact ID to be assigned), and a list of running xact IDs * in the range xmin <= xid < xmax.  It is used as follows: *		All xact IDs < xmin are considered finished. *		All xact IDs >= xmax are considered still running. *		For an xact ID xmin <= xid < xmax, consult list to see whether *		it is considered running or not. * This ensures that the set of transactions seen as "running" by the

⌨️ 快捷键说明

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