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 + -
显示快捷键?