xact.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,442 行 · 第 1/5 页

C
2,442
字号
/*------------------------------------------------------------------------- * * xact.c *	  top level transaction system support routines * * See src/backend/access/transam/README for more information. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.215.2.1 2005/11/22 18:23:05 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <time.h>#include <unistd.h>#include "access/multixact.h"#include "access/subtrans.h"#include "access/twophase.h"#include "access/xact.h"#include "catalog/heap.h"#include "catalog/index.h"#include "catalog/namespace.h"#include "commands/async.h"#include "commands/tablecmds.h"#include "commands/trigger.h"#include "executor/spi.h"#include "libpq/be-fsstubs.h"#include "miscadmin.h"#include "storage/fd.h"#include "storage/proc.h"#include "storage/procarray.h"#include "storage/smgr.h"#include "utils/flatfiles.h"#include "utils/guc.h"#include "utils/inval.h"#include "utils/memutils.h"#include "utils/portal.h"#include "utils/relcache.h"#include "utils/resowner.h"#include "pgstat.h"/* *	User-tweakable parameters */int			DefaultXactIsoLevel = XACT_READ_COMMITTED;int			XactIsoLevel;bool		DefaultXactReadOnly = false;bool		XactReadOnly;int			CommitDelay = 0;	/* precommit delay in microseconds */int			CommitSiblings = 5; /* # concurrent xacts needed to sleep *//* *	transaction states - transaction state from server perspective */typedef enum TransState{	TRANS_DEFAULT,	TRANS_START,	TRANS_INPROGRESS,	TRANS_COMMIT,	TRANS_ABORT,	TRANS_PREPARE} TransState;/* *	transaction block states - transaction state of client queries * * Note: the subtransaction states are used only for non-topmost * transactions; the others appear only in the topmost transaction. */typedef enum TBlockState{	/* not-in-transaction-block states */	TBLOCK_DEFAULT,				/* idle */	TBLOCK_STARTED,				/* running single-query transaction */	/* transaction block states */	TBLOCK_BEGIN,				/* starting transaction block */	TBLOCK_INPROGRESS,			/* live transaction */	TBLOCK_END,					/* COMMIT received */	TBLOCK_ABORT,				/* failed xact, awaiting ROLLBACK */	TBLOCK_ABORT_END,			/* failed xact, ROLLBACK received */	TBLOCK_ABORT_PENDING,		/* live xact, ROLLBACK received */	TBLOCK_PREPARE,				/* live xact, PREPARE received */	/* subtransaction states */	TBLOCK_SUBBEGIN,			/* starting a subtransaction */	TBLOCK_SUBINPROGRESS,		/* live subtransaction */	TBLOCK_SUBEND,				/* RELEASE received */	TBLOCK_SUBABORT,			/* failed subxact, awaiting ROLLBACK */	TBLOCK_SUBABORT_END,		/* failed subxact, ROLLBACK received */	TBLOCK_SUBABORT_PENDING,	/* live subxact, ROLLBACK received */	TBLOCK_SUBRESTART,			/* live subxact, ROLLBACK TO received */	TBLOCK_SUBABORT_RESTART		/* failed subxact, ROLLBACK TO received */} TBlockState;/* *	transaction state structure */typedef struct TransactionStateData{	TransactionId transactionId;	/* my XID, or Invalid if none */	SubTransactionId subTransactionId;	/* my subxact ID */	char	   *name;			/* savepoint name, if any */	int			savepointLevel; /* savepoint level */	TransState	state;			/* low-level state */	TBlockState blockState;		/* high-level state */	int			nestingLevel;	/* nest depth */	MemoryContext curTransactionContext;		/* my xact-lifetime context */	ResourceOwner curTransactionOwner;	/* my query resources */	List	   *childXids;		/* subcommitted child XIDs */	Oid			currentUser;	/* subxact start current_user */	bool		prevXactReadOnly;		/* entry-time xact r/o state */	struct TransactionStateData *parent;		/* back link to parent */} TransactionStateData;typedef TransactionStateData *TransactionState;/* * childXids is currently implemented as an Oid List, relying on the * assumption that TransactionIds are no wider than Oid.  We use these * macros to provide some isolation in case that changes in the future. */#define lfirst_xid(lc)				((TransactionId) lfirst_oid(lc))#define lappend_xid(list, datum)	lappend_oid(list, (Oid) (datum))/* * CurrentTransactionState always points to the current transaction state * block.  It will point to TopTransactionStateData when not in a * transaction at all, or when in a top-level transaction. */static TransactionStateData TopTransactionStateData = {	0,							/* transaction id */	0,							/* subtransaction id */	NULL,						/* savepoint name */	0,							/* savepoint level */	TRANS_DEFAULT,				/* transaction state */	TBLOCK_DEFAULT,				/* transaction block state from the client								 * perspective */	0,							/* nesting level */	NULL,						/* cur transaction context */	NULL,						/* cur transaction resource owner */	NIL,						/* subcommitted child Xids */	0,							/* entry-time current userid */	false,						/* entry-time xact r/o state */	NULL						/* link to parent state block */};static TransactionState CurrentTransactionState = &TopTransactionStateData;/* * The subtransaction ID and command ID assignment counters are global * to a whole transaction, so we do not keep them in the state stack. */static SubTransactionId currentSubTransactionId;static CommandId currentCommandId;/* * This is the value of now(), ie, the transaction start time. * This does not change as we enter and exit subtransactions, so we don't * keep it inside the TransactionState stack. */static TimestampTz xactStartTimestamp;/* * GID to be used for preparing the current transaction.  This is also * global to a whole transaction, so we don't keep it in the state stack. */static char *prepareGID;/* * List of add-on start- and end-of-xact callbacks */typedef struct XactCallbackItem{	struct XactCallbackItem *next;	XactCallback callback;	void	   *arg;} XactCallbackItem;static XactCallbackItem *Xact_callbacks = NULL;/* * List of add-on start- and end-of-subxact callbacks */typedef struct SubXactCallbackItem{	struct SubXactCallbackItem *next;	SubXactCallback callback;	void	   *arg;} SubXactCallbackItem;static SubXactCallbackItem *SubXact_callbacks = NULL;/* local function prototypes */static void AssignSubTransactionId(TransactionState s);static void AbortTransaction(void);static void AtAbort_Memory(void);static void AtCleanup_Memory(void);static void AtAbort_ResourceOwner(void);static void AtCommit_LocalCache(void);static void AtCommit_Memory(void);static void AtStart_Cache(void);static void AtStart_Memory(void);static void AtStart_ResourceOwner(void);static void CallXactCallbacks(XactEvent event);static void CallSubXactCallbacks(SubXactEvent event,					 SubTransactionId mySubid,					 SubTransactionId parentSubid);static void CleanupTransaction(void);static void CommitTransaction(void);static void RecordTransactionAbort(void);static void StartTransaction(void);static void RecordSubTransactionCommit(void);static void StartSubTransaction(void);static void CommitSubTransaction(void);static void AbortSubTransaction(void);static void CleanupSubTransaction(void);static void PushTransaction(void);static void PopTransaction(void);static void AtSubAbort_Memory(void);static void AtSubCleanup_Memory(void);static void AtSubAbort_ResourceOwner(void);static void AtSubCommit_Memory(void);static void AtSubStart_Memory(void);static void AtSubStart_ResourceOwner(void);static void ShowTransactionState(const char *str);static void ShowTransactionStateRec(TransactionState state);static const char *BlockStateAsString(TBlockState blockState);static const char *TransStateAsString(TransState state);/* ---------------------------------------------------------------- *	transaction state accessors * ---------------------------------------------------------------- *//* *	IsTransactionState * *	This returns true if we are currently running a query *	within an executing transaction. */boolIsTransactionState(void){	TransactionState s = CurrentTransactionState;	switch (s->state)	{		case TRANS_DEFAULT:			return false;		case TRANS_START:			return true;		case TRANS_INPROGRESS:			return true;		case TRANS_COMMIT:			return true;		case TRANS_ABORT:			return true;		case TRANS_PREPARE:			return true;	}	/*	 * Shouldn't get here, but lint is not happy without this...	 */	return false;}/* *	IsAbortedTransactionBlockState * *	This returns true if we are currently running a query *	within an aborted transaction block. */boolIsAbortedTransactionBlockState(void){	TransactionState s = CurrentTransactionState;	if (s->blockState == TBLOCK_ABORT ||		s->blockState == TBLOCK_SUBABORT)		return true;	return false;}/* *	GetTopTransactionId * * Get the ID of the main transaction, even if we are currently inside * a subtransaction. */TransactionIdGetTopTransactionId(void){	return TopTransactionStateData.transactionId;}/* *	GetCurrentTransactionId * * We do not assign XIDs to subtransactions until/unless this is called. * When we do assign an XID to a subtransaction, recursively make sure * its parent has one as well (this maintains the invariant that a child * transaction has an XID following its parent's). */TransactionIdGetCurrentTransactionId(void){	TransactionState s = CurrentTransactionState;	if (!TransactionIdIsValid(s->transactionId))		AssignSubTransactionId(s);	return s->transactionId;}static voidAssignSubTransactionId(TransactionState s){	ResourceOwner currentOwner;	Assert(s->parent != NULL);	Assert(s->state == TRANS_INPROGRESS);	if (!TransactionIdIsValid(s->parent->transactionId))		AssignSubTransactionId(s->parent);	/*	 * Generate a new Xid and record it in PG_PROC and pg_subtrans.	 *	 * NB: we must make the subtrans entry BEFORE the Xid appears anywhere in	 * shared storage other than PG_PROC; because if there's no room for it in	 * PG_PROC, the subtrans entry is needed to ensure that other backends see	 * the Xid as "running".  See GetNewTransactionId.	 */	s->transactionId = GetNewTransactionId(true);	SubTransSetParent(s->transactionId, s->parent->transactionId);	/*	 * Acquire lock on the transaction XID.  (We assume this cannot block.) We	 * have to be sure that the lock is assigned to the transaction's	 * ResourceOwner.	 */	currentOwner = CurrentResourceOwner;	PG_TRY();	{		CurrentResourceOwner = s->curTransactionOwner;		XactLockTableInsert(s->transactionId);	}	PG_CATCH();	{		/* Ensure CurrentResourceOwner is restored on error */		CurrentResourceOwner = currentOwner;		PG_RE_THROW();	}	PG_END_TRY();	CurrentResourceOwner = currentOwner;}/* *	GetCurrentTransactionIdIfAny * * Unlike GetCurrentTransactionId, this will return InvalidTransactionId * if we are currently not in a transaction, or in a transaction or * subtransaction that has not yet assigned itself an XID. */TransactionIdGetCurrentTransactionIdIfAny(void){	TransactionState s = CurrentTransactionState;	return s->transactionId;}/* *	GetCurrentSubTransactionId */SubTransactionIdGetCurrentSubTransactionId(void){	TransactionState s = CurrentTransactionState;	return s->subTransactionId;}/* *	GetCurrentCommandId */CommandIdGetCurrentCommandId(void){	/* this is global to a transaction, not subtransaction-local */	return currentCommandId;}/* *	GetCurrentTransactionStartTimestamp */TimestampTzGetCurrentTransactionStartTimestamp(void){	return xactStartTimestamp;}/* *	GetCurrentTransactionNestLevel * * Note: this will return zero when not inside any transaction, one when * inside a top-level transaction, etc. */intGetCurrentTransactionNestLevel(void){	TransactionState s = CurrentTransactionState;	return s->nestingLevel;}/* *	TransactionIdIsCurrentTransactionId */boolTransactionIdIsCurrentTransactionId(TransactionId xid){	TransactionState s;	/*	 * We always say that BootstrapTransactionId is "not my transaction ID"	 * even when it is (ie, during bootstrap).	Along with the fact that	 * transam.c always treats BootstrapTransactionId as already committed,	 * this causes the tqual.c routines to see all tuples as committed, which	 * is what we need during bootstrap.  (Bootstrap mode only inserts tuples,	 * it never updates or deletes them, so all tuples can be presumed good	 * immediately.)	 */	if (xid == BootstrapTransactionId)		return false;	/*	 * We will return true for the Xid of the current subtransaction, any of	 * its subcommitted children, any of its parents, or any of their	 * previously subcommitted children.  However, a transaction being aborted	 * is no longer "current", even though it may still have an entry on the	 * state stack.	 */	for (s = CurrentTransactionState; s != NULL; s = s->parent)	{		ListCell   *cell;		if (s->state == TRANS_ABORT)			continue;		if (!TransactionIdIsValid(s->transactionId))			continue;			/* it can't have any child XIDs either */		if (TransactionIdEquals(xid, s->transactionId))			return true;		foreach(cell, s->childXids)		{			if (TransactionIdEquals(xid, lfirst_xid(cell)))				return true;		}	}	return false;

⌨️ 快捷键说明

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